I started doing some research into .Net design principles to support the effort in partitioning development activities when designing a class library. In particular, the pmFx class library. Of course, there are great OO design principles(that will help tremendously but what if I want to share the effort of developing a single class with other people? Certainly text merging is helpful, but a bit messy during early development when there is a lot of file-wide churn. What else is there to support early work on class design with more than one developer?
Aside from seeing partial classes as the result of codegen, I hadn't used them. It seemed like a good concept to do some research on. I even started laying out the a simple class library using partial classes. It became apparent that using partial classes as a means to break-up large files requires thought and care. Here is what I found and further down are some references that clarify and expand on my initial observations:
- Partial classes can break coding standards - If your coding standard says something like "place all instance data at the top of the class and arrange them in groups of related data" and you use partial classes, you might have some explaining to do regarding breaking your standard. If the purpose of using partial classes is to separate related class data and functionality into distinct files, then it follows that your instance data for the "part" of the class you are working on needs to be placed in your file. This means that developers will have to navigate through multiple files to see all the instance data, which is not wonderful. Take this a step further if you like to arrange your class source by member type, protection, or another organizational scheme. In my case, I place static members first, instance data next, followed by constructors, followed by events, followed by public methods, and finally all private methods are placed toward the end of the file. This is just my preference. If you use partial classes, you potentially will have members of all types spread out across multiple files.
- Without tools such as the class view, partial classes make seeing the big picture difficult - If a class implementation is spread across multiple files, seeing the big picture complete with all the assumptions, related data, related methods, and comments requires either hitting F12 a lot or loading up the class view tools in Visual Studio. I prefer never to touch my mouse when writing or reading code. I prefer a clean workspace without 652 tool windows glued on. I don't mind deep source if it is well written and pretty. I don't want to use some overlay to get a sense for how a class is structured. Again, these are just my preferences and my be the result of my early days writing straight C and C++.
- I like code folding and regions - Our coding standard asks that we avoid files with more than 500 lines (excluding whitespace and excepting files generated by tools). Even a file of 499 lines can be a lot of source to stare at so I use regions and Visual Studio's code folding features to hide what I don't wan to look at. See the image to the right. Selecting a region header and typing CTRL+MM will toggle the code-folding. With enough practice, you can toggle folding very quickly and focus in just what you want to see
- Partial classes have little to do with OO - If you are using partial classes to break up files that are too large, then you might have a deeper problem: should your class be refactored into multiple classes? Aside from potentially being a red flag when used as a substitute for good OO, partial classes have very little to do with object oriented design. In my opinion, partial classes are just code-folding a the file-level.
- One class, one file - We like to have one class per file, even if a class is nested. With partial classes you are now able to have one class, multiple files--which reminds me of the badness of having more than one class per file. Why is having more than one class per file bad? Maintainability, readability, supporting team development (I own this class thus this file, you own that class thus that file), among other things. So, why is it okay now to have one class with multiple files? I think in the case were you need to separate machine generated code from developer code, this makes a lot of sense--and solving this problem apparently was the key motivator behind the introduction of partial classes.
- Separate church and state - Mentioned above, partial classes are valuable when separating machine generated code from developer code. WebForms and WebForms do this in .Net 2.0 and beyond. Another place where this is done is the data designers in VS2005 and VS2008. Implementing strongly typed datasets with partial classes means that the CRUD operations of the dataset can be desperate from domain logic.
- House interface implementations in separate files? - Dino Esposito points out that partial classes are useful if you are implementing more than one interface. You may have a class that implements SoapHttpClientProtocol, IDisposable, and also contains a swath of domain logic. In this case, the class could be split apart into MyClass.cs (domain logic), MyClass.SoapHttpClientProtocol.cs (SoapHttpClientProtocol implementation),and MyClass.IDisposable.cs (IDisposable implementation). I like partial classes for this purpose but points 1 & 2 still hold.
I think the biggest issue with partial classes is that classes are encapsulations of data and functionality representing a Thing and partial classes, while still ultimately the Thing, now have many file parts. The hesitance to use partial classes stems from the mental inertia that has racked up over the years regarding classes the best organizing principle for code and that classes have lived in one file for so long. That mental inertia can be overcome if the benefits of partial classes outside of separating developer code from machine-generated code, can come into clearer view. My hesitation to use partial classes to assist in splitting up development activities taken on a single class comes from the issue of shared state. After all, a class is still a class and a class has internal state it shares across members. If I have multiple files each containing state then I run the risk of not having all my state available to me for modification during development or I run the risk of changing state that other file-owners on the class rely on.