Like I said before, I really dislike try/catches. They slow your code down and they are generally used when you don't know how to appropriatly handle data. For example, using try/catch to convert a string to an int versus using Int32.TryParse(). Yes, I've really seen this on the wild... and not from an amatuer either. I'll openly admit, I'm an OK programmer. I have much to learn. I just learned how to implement Transactions in code. I have learned how to make .NET crash so hard -- it throws an exception *outside* of your applications domain. This means you can't catch it. At all. But I'll get to that in a minute. I'd like to start by explaining when it's a good idea to use a try/catch.
Using try/catches are a good when you can't calculate everything. For example, network issues. Sure -- you can ping a server. Doesn't mean the database is up. Sure, you can do many other things such as test the database (SELECT 0 comes to mind) however you can't calculate the network being dropping in the middle of everything. So far the only method I've found that is reliable is using a try/catch because the medium is so volatile, even after doing your check it can go down. So, the answer is to use a transaction (if you are doing multiple inserts) and using a try/catch looking for a SqlException. But this won't stop everything... I'll explain how I pissed off .NET with pictures and network failures.
Apaprently .NET handles System.Image in an intersting way. It is only a pointer/reference to the location of the file. What this means is that if you reference an image across the network and it goes down -- System.Image throws an exception. In fact it throws a pretty gnarly exception that you can't catch. Here is how you can reproduce this. Create a blank project. Drop in a timer and set the interval to 15 second or an amount that a little longer than it will take you to unplug your network cable. Modify the form load to engage the timer and have the form load the image. Have the form hide itself. On the timer tick, have the form display itself (this will cause the image to be repointed and thus having to look at the network to pull the image). Start the app and then unplug your network cable. It should have a nasty crash. One you can't stop. Another thing I learned is that it puts a lock on the file so you can't delete/modify it. So far the only idea I've come up with to have an in-memory cache is to load it in to a byte array from a stream and have you rference that byte array. What I don't know is if it's still a pointer to the file. I might assume that that stream will push the bits in to the byte array and thusly remove the dependance of the network.
Using SubSonic the code to implement transactions and SqlException is pretty straight foreward and you would just surround your .Saves (personally, I like to place everything in the try/catch block just to make the code look cleaner) with a System.Transactions.TransactionScope. A TransactionScope will put a lock on your table when doing an insert, and for good reason. This is because you can't rely on the data to be inserted until you do a commit. So this will stop people from seeing the data (or any in the table for that matter) so they don't reference it and then have the transaction cancelled and then you have an inconsistant database. If you want a way around that then you should use System.Transactions.TransactionOptions. TO has only two properties -- timeout and the scope options. Microsoft has an article explaining the enumerations and their values and which ones you would want to use for which circumstances. I should probably link it but I'm too lazy.
For what it's worth I've decided to re-focus on certain things.
Two of the computer aspects are: OpenBSD and programming (C#, .NET 2.0 compatible code, but some is 3.5).
I want to update the OpenBSD-Wiki and start making major progress on the MetaDataSystem. I've made good progress with it so far using SubSonic and SQLite. A few gotchya here and there though.
The third thing is going to the gym more religously. I'm pretty reliably at going at least twice a week doing 3 body parts each day. The pattern is usually Back/Bi/Legs and Chest/Tri/Shoulders with at least a day rest in between.
I think I'm going to switch that to Monday and Wednesday are workouts with minor aerobic while Tuesday and Thursday are major aerobic and swimming and relaxing in the spa. Sundays I'm trying to get out and swim at the local pool. Alochol is usually involved there. Saturday nights usually involve alcohol too... and be being an idiot, but that's half the fun isn't it? going "I just did NOT do what I think I did? FUCK!". Usually laughing about it the next day.
So I had an intersting discussion with the guys at work about try/catches.
My opinion is slowly becoming: Try/Catches are habits of poor skill in programmers.
Sure, sometimes you need to use them merely to be sure. Or global try/catches *just to be safe*, sure, but relying on them -- I believe it's poor coding.
The argument they brought up was "so, what -- you're supposed to use if's for *everything*?" to which my response (now) is "what? you use try/catches in *everything* method?" -- which I know they don't -- and it bit us.
You see, in a DataGridCellMouseClick or some event simliar to that you can have it attempt to calculate what cell it's in. So, we had something like:
int SomeVal = Convert.ToInt32(DataGridObject.Cells[e.Cell.Row,e.cell.Column].Value.ToString());
Sounds simple, right?
Well, turns out if you click on a column -- it barfs (either row or colum will be < 0 if you click them). So, ok -- to what extent do you do sanity check on data? It's awfully unreasonble to do sanity checking on *everything* *everytime*. So, perhaps you should just do it when you intiate it?
The net result was something close to:
if ( e.Cell.Row < 1 || e.Cell.Row < 1)
/* Assume they clicked on a header column or row */
int SomeVal = Convert.ToInt32(DataGridObject.Cells[e.Cell.Row,e.cell.Column].Value.ToString());
Something I have learned while writing a migration app is that try/catches slow you down an amount that is not insignificant. A couple million times and you are looking at adding minutes or *hours* to your app. So not only have I learned this habit because it made my app much slower, I learned you should pay more attention to your code.
Perhaps slowing down coding to make code cleaner is a better idea. Think it through.
I found a few comments around the net about this too and it seems that some believe try/catches are so infignificant that you should use them freely while others will say that using a try/catch because you don't do proper parsing / variable handling just shows poor coding skills. A very common one is DateTime.Parse versus using DateTime.TryParse -- which I should use Int32.TryParse above (go figure).
On an important note, I do understand (and use myself) try/catches for play-pen type code. Things that *can't* faily, however, I don't allow try/catches. For example, migrations -- they *can not* fail. Ever. Peroid. Hitting a try/catch means *I* fucked up somewhere or someone pulled a network cable (which I need to research how to check for that anyways).
That is a pretty funny link.
Someone posted this under the title "If you don't use this, you are like a doctor who doesn't believe in germs." I'll agree with that to a certain extent.
Here is a link which explains unicode. I spent some time on this before and have started trying to implement a more language netural code conciously. I've done the same on my wiki's and blogs.
I'm in the process of getting an app going under .NET 3.0 using Visual Studio 2008 to see the differences in speed between Linq, SubSonic, and using a plain SQLDataAdapter. Yes, I'm well aware using a DataReader / DataAdapter is going to be faster -- the question is: How much faster? Is it worth making the code that much more cleaner? What about if the code is only going to be used once 4 months from now and, hopefully, never touched again? My problem is I want something to be as fast as possible without making code ugly and without spending a lot of time tweaking -- so I'm taking the shotgun approach. At the moment, it seems like they are all fairly close unless you are dealing with LOTS (millions) of records -- which I am not. SubSonic has its fair share of bugs such as puking if a table doesn't have a primary key. I can understand it not understanding how to right back or do complex queries, I just want to populate a collection with a 'Select *' type statement -- so it doesn't need a care about primary keys as I'm just going to loop through item in the collection and pull data as I see fit. Also, SubSonic seems to always do a 'SELECT *' type query if I want to use the simple code such as 'Some_DB.Some_TableCollection TC = new Some_DB.Some_TableCollection().Load();'. If I want to be specific then I have to use a Query class. Even worse, it's /horrible/ at doing OR's. They really prefer you to use views or stored procedures. Neither of those are bad, but I'm not writing code for something anyone else but me should be using -- so I don't care about exploits or any safety measures. Even if I was, this engine doesn't have any direct input mechanism, so good luck with that. Linq seems overly complicated. Fucking A is it a bitch to setup. Nothing seems automatic. Code doesn't /feel/ cleaner (so far from my, admittedly, little testing). Google doesn't seem to know how to use it either. I'm finding contradicting information. So, this means I have to do a "best case scenario" speed test to get both Linq and SubSonic working, which isn't a bad idea. One of the programming styles I learned was "assume everything will work perfectly, *then* make exceptions". The alternative, which is more common, is plan for the worst then if it's the best do X. The problem with that is you are always occurring the overhead of the worst instead of doing the best first and if it fails (Which it rarely should) then go to some exception handling. This places me back at square 1. Here is my game plan:
I'm also probably going to try some of this code on other DB engines such as MySQL and SQLite.
So I've started grepping the code for stuff.
I decided to start with the simple stuff -- the items in /bin.
I'm currently printing /bin/cp's files. I understand most of the C syntax but some of it seems so very complicated I can't wrap my mind around it. Sooo.. I'll do the next bext thing: Print it out so I can read it on the crapper.
I'm currently groking the 4.2 code and plan on eventually following -current and subscribing to the CVS mailing list when I think I'm 'good enough' (by my standards) to be able to understand what is going on and not waste bandwidth and their time.
We'll see how well I do... wish me luck. Or not. I'm doing it anyways. :-P