Sunday, February 14, 2016

One Class Per File

I've been using C# as one of my primary languages for the past 6 years where I currently work. Prior to that I was working with Java. One of the immediate differences that I noticed was that it was not uncommon to have multiple public classes in a source file. C# allows it, so why not.

Coming from a Java background I was used to one public class per file, where the filename needed to match the public classname in the file, and for me... I preferred it that way. I felt that it helped to organize the code. Some may say, having multiple classes in a file can aid in readability/discoverability/understandability/insert-an-ability. All true, they can. It can also be harmful in each of those respects as well... all depends. 

This week I've discovered a new reason why I prefer one class per file. Changes to classes are more traceable if a class has it's own file. Huhhh?

The reasoning goes like this. If I start out and have a couple of small public classes in a file, then tracking changes doesn't seem too difficult. The problem comes in when the classes grow. Your file will becomes larger and larger, and when you look at the file, there might all of a sudden be too many concepts in the file for you to keep track of. This can especially be the case where you can have a file named a name that has nothing to do with any of the classes inside of it (poor form imo, but to each his own). Some of the classes in the file may be related to the filename, but if sloppiness has crept in (not unheard of) then other classes may not be as closely related to that filename. Different concepts and abstractions may have crept into the file, and you may not realize it for a while. Yuck.

Then one day your in the file and your like, ZOMG, this file is too large and has too many concepts in it, I have to tease it apart. And so you do. You become the boy scout and you tease classes out of it, putting them in their respective files with the respective filenames and namespaces. And when you do this, your original file can in the worst case be empty (remember, the filename doesn't have to match any of the classes, and you just teased all of the classes out). And so you delete it. No problemo dude. And then you commit it and push it up to the remote (because your working in git).

And now, well now all of the history that you had in commit messages is gone for every class that was in the original file. It's not like renaming a file in git. You can always use the `--follow` flag on the current file you have to retrieve the full commit history for that file.

git log --follow path/to/filename 

Unless your a good tracker, chances are you're not going to re-discover where those commit messages went for the deleted file. Perhaps you'll never need to. I hope so.

Commit messages are a blessing for both me and my fellow developers because they are in some part a diary of what we were thinking about when we made changes. I've been getting more and more accustomed to making rather large commit messages lately. I'm recording more of the thoughts that I had around the design choices I've used, and perhaps even recording patterns I used in the commit.

The history of changes to a class is important to me. Maybe I've found some religion on this issue, and most probably, I'm going to be more prudent on keeping... one public class per file come Monday.

Brad Abrams - Design Guidelines, Managed code and the .NET Framework
- Source files should contain only one public type, although multiple internal classes are allowed

No comments:

Post a Comment