MSDN Magazine - October 2008 - (Page 48) I learned the hard way that even innocuous-looking duplication can cause headaches. With the advent of generics in the Microsoft .NET Framework 2.0, many people started creating parameterized Repository classes that looked something like this: public interface IRepository { void Save(T subject); void Delete(T subject); } Code Smells when designing new code, but it might be even more important to recognize when your existing code or design has developed problems. Like inappropriate intimacy, “code smell” (defined by martin Fowler in the book Refactoring: Improving the Design of Existing Code) is a tool that you can utilize to spot potential problems in code. A code smell is a sign that something may be wrong in your code. it doesn’t mean that you need to rip out your existing code and throw it away on the spot, but you definitely need to take a closer look at the code that gives off the offending “smell.” A code smell can be spotted by simple inspection. learning about code smells is a powerful tool to remove little problems in your code and class design before those problems become bigger issues. many, if not most, of the commonly described code smells are signs of poor cohesion or harmful tight coupling. Here are some other examples: Divergent Changes A single class that has to be changed in different ways for different reasons. This smell is a sign that the class is not cohesive. you might refactor this class to extract distinct responsibilities into new classes. Feature Envy A method in ClassA seems way too interested in the workings and data fields of ClassB. The feature envy from ClassA to ClassB is an indication of tight coupling from ClassA to ClassB. The usual fix is to try moving the functionality of the interested method in ClassA to ClassB, which is already closer to most of the data involved in the task. Shotgun Surgery A certain type of change in the system repeatedly leads to making lots of small changes to a group of classes. Shotgun surgery generally implies that a single logical idea or function is spread out over multiple classes. Try to fix this by pulling all the parts of the code that have to change together into a single cohesive class. It’s obviously good to know how to do the right things In this interface, T would be a domain entity like Invoice or Order or Shipment. Users of StructureMap wanted to be able to call this code and get a fully formed repository object that could handle a specific domain entity, such as an Invoice object: IRepository repository = ObjectFactory.GetInstance<IRepository >(); It sounded like a great feature to have, so I sat down to add support for these kinds of parameterized types. Making this change to StructureMap turned out to be very difficult because of code like this: _PluginFamilies.Add(family.PluginType.FullName, family); And code like this: MementoSource source = this.getMementoSourceForFamily(pluginType.FullName); And code like this as well: private IInstanceFactory this[Type PluginType] { get { return this[PluginType.FullName]; } set { this[PluginType.FullName] = value; } } Have you spotted the duplication yet? Not to get too involved with this sample, but I had an implicit rule that stated that objects related to a System.Type were stored by using the Type.FullName property as the key in a Hashtable. It’s a tiny little bit of logic, but I had duplicated it all over the codebase. When I implemented generics, I determined that it would be better if I stored objects internally by the actual type instead of Type.FullName. This seemingly minor change in behavior took me days instead of the hours I assumed up front because of how many times I had duplicated this little bit of data. The lesson learned here is that any rule in your system, no matter how seemingly trivial, should be expressed once, and only once. Wrapping Up Cohesion and coupling applies to every level of a design and architecture, but I’ve mostly focused on fine-grained details at the class and method levels. Sure, you better get the big architectural decisions right—technology selection, project structure, and physical deployment are all important, but usually these are fairly constrained in the number of choices and the trade-offs are generally well understood. I’ve found that the cumulative effect of the hundreds and thousands of little decisions you make at the class and method levels add up to have a more profound impact on the success of a project—and you’ve got a far greater range of choices and alternatives in regard to the little things. While it may not be true of life in general, in software design, sweat the small things. 48 msdn magazine There’s a common attitude with developers that worrying about all this cohesion and coupling stuff is ivory tower theory that detracts from getting the work done. My feeling is that good cohesion and coupling qualities in your code will sustain productivity in your code over time. My strong advice is to internalize your recognition of cohesion and coupling qualities to the point where you don’t have to consciously think about these qualities. Moreover, one of the best exercises I can recommend for improving your design skills is to revisit your previous coding efforts, try to find ways you could have improved the old code, and try to remember the elements of your past design that either made changing the code easy or made adjusting the code difficult. Jeremy miller, a Microsoft MVP for C#, is also the author of the open source StructureMap (structuremap.sourceforge.net) tool for Dependency Injection with .NET and the forthcoming StoryTeller (storyteller.tigris.org) tool for supercharged FIT testing in .NET. Visit his blog, “The Shade Tree Developer,” at codebetter.com/ blogs/jeremy.miller, part of the CodeBetter site. Patterns in Practice http://structuremap.sourceforge.net http://storyteller.tigris.org http://www.codebetter.com/blogs/jeremy.miller http://www.codebetter.com/blogs/jeremy.miller
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.