I should probably begin this blog post with a declaration: I am NOT trying to start a war amongst technologists. The ideas presented below can be somewhat divisive, but are not intended to be. The objective is to wrap up our series on Iterating Towards Excellence, and provide a set of rules or principles to help you accomplish at least three goals.
Each team member will become a better developer
The entire team will be more consistent in approach and practice
The final product will be easier to maintain
Like any set of conventions, there are communities that support them fully, support a subset, or prefer a completely different set. I am perfectly comfortable with whichever community you aspire or belong to. If you disagree, all I ask is that you clearly communicate your preferred conventions and reasoning to your team. If the team finds itself constantly improving in the areas listed above, you already have a good set of development standards, and I applaud you for deriving and enforcing them.
The scope of this blog post will cover two main areas: object-oriented standards and major semantic standards. It is not intended to be completely exhaustive. Rather, it’s to provide you with a head start towards setting your own standards and to consider other standards your team can eventually adopt.
There are a set of standards that should be followed in order to help developers adhere to good object- orientation. Two of the most important standards are single purpose and relative size for classes and methods.
Transform your business operations with our Microsoft solutions
This is a fundamental object-oriented concept, but I’m still surprised at how often I see this concept ignored. A class should have a single purpose and each method within the class should have a single purpose. This will keep your objects small, and easy to test and maintain. One of the most common violations of this principle is the implementation of a method that makes multiple decisions and behaves differently based on those decisions. When you see decision structures such as “if” statements that have multiple inputs, that decision can and should be refactored into a separate method. The new method will have the single responsibility of making the decision, and the original method can continue the core implementation. Take a look at the following snippet.
If you’ve been following along in this blog series, you might recognize the code from the TDD blog post. The Next method shown above has a responsibility to determine when the next business day takes place. However, it currently has to determine if the next business day is a day that falls over the weekend. Based on which weekend day it is, it does two different things. The entire decision structure can and should be refactored out to keep the cohesion high, as shown below.
When you finish coding a method, check the implementation for decision structures and branching logic. If found, consider refactoring the method. The decisions and branching can go in separate methods. That way, the original method can more succinctly go about its business.
Classes should have a single purpose. They should be constructed using methods that also have single purposes. Therefore, no method should be larger than what is required to fulfill its purpose. Likewise, the class should not be larger than what is required to hold the collections of methods that fulfill the class’s purpose. This will lead to a larger number of methods and classes, each of which has fewer lines than normal.
I do not abide by an “x number of lines of code per method or class” mandate. However, if you have a method that takes up more than a screen of display, there is a good chance that the method is doing more than it should. Similarly, if you have a class that takes up more than a few screens of display, check for high cohesion amongst the methods. You will probably need to split the class so it is has a smaller responsibility.
Beyond the standards that support object-orientation, there are more semantic standards that make the team more productive, and the code more readable and maintainable. They include naming and commenting conventions.
I used to frequently play Infocom games, including: Zork, Enchanter, and Hitchhiker’s Guide to the Galaxy. These were popular, text-based games for owners of Commodore 64s. One of my favorite settings in the game was “maximum verbosity” where the game would emit the full-text of each action taken. I always knew what was going on because the full-context of every action was reflected with practically every command entered.
The same is true of variable, method, and class names. They should use sensible words, preferably ones that describe the business domain, and be long enough to accurately describe their usage and intent. For example, when working on a booking system in the past, I had a class called CurrentWeekBindableBookingListSortStrategy. That might seem like a mouthful, but I preferred typing it to interpreting something like CurWkBindBkngListSortStrat or something more obscure like SortStrategy. When someone looks at that class name, they can assume the intent is to sort lists of “bindable bookings” for the “current week.”
That’s easy enough for classes, but what about methods? The same rules apply for using meaningful, business-centric wording. Personally, I don’t have a strong preference of GetUserById(id) versus UserFor(id). The rule is that the method name should be descriptive of the intent of the functionality. However, once you decide on the verbiage, stick to it throughout the code base.
Variable names should follow the same guidelines as described above. Additionally, don’t use Hungarian notation. It used to be true that languages were weakly typed and the variable name length had a maximum value. Hungarian notation helped developers remember what type of data a variable held with the tersest description possible. Today, most compiled languages are strongly typed. Likewise, most compilers enforce data type constraints for their languages and no longer have a limitation on variable name length. Given these facts, Hungarian notation doesn’t add value and should be avoided.
Don’t be afraid to set your naming convention to maximum verbosity.
Attempt to avoid all comments in code.
This one is sure to set some people off. It’s a very common practice to pseudo-code something with comments and then fill in the code that satisfies the intent of the comments. However, there are a few problems with that approach. Once comments are in the code, they have to be maintained and CANNOT be exercised via a test of any kind. When the business rule that governs a section of code changes, the code AND the comment must be changed.
My rule of thumb is that if I need to add a comment, I should first consider revising the code so it is self-documenting. Can I use a more descriptive variable or method name? Should I refactor out some decision-making code so that the intent of the decision is surfaced via a method name?
However, there may be times when comments are necessary. If a decision has been made that cannot be expressed through code, adding a comment may be essential. Be VERY careful with this exception, as it can easily be abused by team members who are less disciplined about rigorous readings of the code.
For those still reading, I commend you for your open-mindedness. Setting development standards based on good object-orientation and important semantics is a great start towards improving the consistency of your team’s output. Do not stop there. Collaborate with your teammates to determine which standards should be adopted immediately and observe the results. Take advantage of your teammates’ experience. Don’t be afraid to try new things. Ultimately, the team needs to agree on the standards. Consensus on standards will help the team achieve the goals of increasing productivity and maintainability.
This blog post marks the end of the series on Iterating Towards Excellence. If you missed the previous posts in this series, we recommend reading Part 1, Part 2, Part 3, and Part 4. If you have questions or comments about development standards or any other topics, please leave them in the comments below or send a tweet to @CrederaMSFT.