|
|
###### [Home](home) / [Digitec Coding Practices](coding-practices) / [Global Coding Standards](global-coding-standards) / Smells and Heuristics - General
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
[:arrow_left: Functions](smells-and-heuristics-functions) | [Names :arrow_right: ](smells-and-heuristics-names)
|
|
|
|
|
|
# General
|
|
|
|
|
|
|
|
|
|
|
|
#### G1: Multiple Languages in One Source File
|
|
|
|
|
|
Today's modern programming environments make it possible to put many different languages into a single source file. For example, a Java source file might contain snippets of XML, HTML, YAML, JavaDoc, English, JavaScript, and so on. For another example, in addition to HTML a JSP file might contain Java, a tag library syntax, English comments, Javadocs, XML, JavaScript, and so forth. This is confusing at best and carelessly sloppy at worst.
|
|
|
|
|
|
The ideal is for a source file to contain one, and only one, language. Realistically, we will probably have to use more than one. But we should take pains to minimize both the number and extent of extra languages in our source files.
|
|
|
|
|
|
|
|
|
#### G2: Obvious Behavior Is Unimplemented
|
|
|
|
|
|
Following "[The Principle of Least Surprise](http://en.wikipedia.org/wiki/ Principle_of_least_astonishment)," any function or class should implement the behaviors that another programmer could reasonably expect. For example, consider a function that translates the name of a day to an `enum` that represents the day.
|
|
|
|
|
|
Day day = DayDate.StringToDay(String dayName);
|
|
|
|
|
|
We would expect the string "Monday" to be translated to `Day.MONDAY`. We would also expect the common abbreviations to be translated, and we would expect the function to ignore case.
|
|
|
|
|
|
When an obvious behavior is not implemented, readers and users of the code can no longer depend on their intuition about function names. They lose their trust in the original author and must fall back on reading the details of the code.
|
|
|
|
|
|
#### G3: Incorrect Behavior at the Boundaries
|
|
|
|
|
|
It seems obvious to say that code should behave correctly. The problem is that we seldom realize just how complicated correct behavior is. Developers often write functions that they think will work, and then trust their intuition rather than going to the effort to prove that their code works in all the corner and boundary cases.
|
|
|
|
|
|
There is no replacement for due diligence. Every boundary condition, every corner case, every quirk and exception represents something that can confound an elegant and intuitive algorithm. _Don't rely on your intuition_. Look for every boundary condition and write a test for it.
|
|
|
|
|
|
#### G4: Overridden Safeties
|
|
|
|
|
|
Chernobyl melted down because the plant manager overrode each of the safety mecha- nisms one by one. The safeties were making it inconvenient to run an experiment. The result was that the experiment did not get run, and the world saw it's first major civilian nuclear catastrophe.
|
|
|
|
|
|
It is risky to override safeties. Exerting manual control over serialVersionUID may be necessary, but it is always risky. Turning off certain compiler warnings (or all warnings!) may help you get the build to succeed, but at the risk of endless debugging sessions. Turn- ing off failing tests and telling yourself you'll get them to pass later is as bad as pretending your credit cards are free money.
|
|
|
|
|
|
#### G5: Duplication
|
|
|
|
|
|
This is one of the most important rules in this book, and you should take it very seriously. Virtually every author who writes about software design mentions this rule. Dave Thomas and Andy Hunt called it the [DRY](http://en.wikipedia.org/wiki/Don't_repeat_yourself) principle (Don't Repeat Yourself). Kent Beck made it one of the core principles of Extreme Programming and called it: "Once, and only once." Ron Jeffries ranks this rule second, just below getting all the tests to pass.
|
|
|
|
|
|
Every time you see duplication in the code, it represents a missed opportunity for abstraction. That duplication could probably become a subroutine or perhaps another class outright. By folding the duplication into such an abstraction, you increase the vocabulary of the language of your design. Other programmers can use the abstract facilities you create. Coding becomes faster and less error prone because you have raised the
|
|
|
abstraction level.
|
|
|
|
|
|
The most obvious form of duplication is when you have clumps of identical code that look like some programmers went wild with the mouse, pasting the same code over and over again. These should be replaced with simple methods.
|
|
|
|
|
|
A more subtle form is the switch/case or if/else chain that appears again and again in various modules, always testing for the same set of conditions. These should be replaced with polymorphism.
|
|
|
|
|
|
Still more subtle are the modules that have similar algorithms, but that don’t share similar lines of code. This is still duplication and should be addressed by using the TEM- PLATE METHOD,4 or STRATEGY5 pattern.
|
|
|
|
|
|
Indeed, most of the design patterns that have appeared in the last fifteen years are sim- ply well-known ways to eliminate duplication. So too the Codd Normal Forms are a strat- egy for eliminating duplication in database schemae. OO itself is a strategy for organizing modules and eliminating duplication. Not surprisingly, so is structured programming.
|
|
|
|
|
|
I think the point has been made. Find and eliminate duplication wherever you can.
|
|
|
|
|
|
#### G6: Code at Wrong Level of Abstraction
|
|
|
|
|
|
It is important to create abstractions that separate higher level general concepts from lower level detailed concepts. Sometimes we do this by creating abstract classes to hold the higher level concepts and derivatives to hold the lower level concepts. When we do this, we need to make sure that the separation is complete. We want all the lower level concepts to be in the derivatives and all the higher level concepts to be in the base class.
|
|
|
|
|
|
For example, constants, variables, or utility functions that pertain only to the detailed implementation should not be present in the base class. The base class should know noth- ing about them.
|
|
|
|
|
|
This rule also pertains to source files, components, and modules. Good software design requires that we separate concepts at different levels and place them in different containers. Sometimes these containers are base classes or derivatives and sometimes they are source files, modules, or components. Whatever the case may be, the separation needs to be complete. We don’t want lower and higher level concepts mixed together.
|
|
|
|
|
|
Consider the following code:
|
|
|
|
|
|
public interface Stack {
|
|
|
Object pop() throws EmptyException;
|
|
|
void push(Object o) throws FullException; double percentFull();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
[:arrow_left: Functions](smells-and-heuristics-functions) | [Names :arrow_right: ](smells-and-heuristics-names) |
|
|
\ No newline at end of file |