NFJS: Cleaning up your code with Neal Ford – level 200

Neal gave some great tips on improving code.  Here’s the rundown.  These are thoughts directly from Neal:

Coding standards aren’t necessary.  They are just preferences that folks in
charge force on underlings.  There are
more important things than coding standards. 
Tools can reformat code to some sort of standard.

#1:  Naming
things:  Use verbose variable names.  Don’t worry about having to type.  Modern IDEs give you these in a drop-down
list, so you only have to type them once. 
IntelliJ and Resharper will guess, and you don’t have to even type them
once.

#2:  Composed
Method:  Comments.  Xml comments are sometimes useful if you need
to generate documentation.  Intra-code
comments are not necessary most of the time. 
No one ever reads them, they smell, and they lie when the code around
them changes (because no one updates them). 
There is nothing that anchor line comments to the code they are supposed
to describe.  At least Xml comments are
anchored to the method.  So, if comments
in code don’t help as much as we’d like, what can we do?  Make the method name be a long, description
of what the method does, and no method should be longer than 5-15 lines of
code.  All public methods should read as
an outline of things that need to be done (and call private methods to get
these things done).

  • Benefits
    of compose method
    • Stack
      traces become easier to read
    • Debugging
      is easer.  Instead of stepping over
      lines of code, you step over private methods that are little chunks of
      work.
    • It
      makes writing unit tests easier because you can fake out any step.
    • It
      makes it easier to identify generic methods that can be pushed up the
      inheritance hierarchy.
    • Once
      the method reads easier, line comments become redundant and unnecessary.

#3:  Apply the Unix
Philosophies:  By applying unix
principles to software will make it better. 

  • Write
    simple parts connected by clean interfaces.
  • Clarity
    is better than cleverness.
  • Design
    programs to be connected to other programs
  • Separate
    policy from mechanism; separate interfaces from engines.
  • Design
    for simplicity; add complexity only where you must
  • Write
    a big program only when it is clear by demonstration that nothing else
    will do.
  • Design
    for visibility to make inspection and debugging easier.
  • Robustness
    is the child of transparency and simplicity.
  • Fold
    knowledge into data so program logic can be stupid and robust.
  • In
    interface design always do the lease surprising thing.
  • When a
    program has nothing surprising to say, it should say nothing.
  • When
    you must fail, fail noisily and as soon as possible.  (Don’t return null if something really
    bad happens).
  • Programmer
    time is expensive; conserve it in preference to machine time.
  • Avoid
    hand-hacking: write programs to write programs when you can.
  • Prototype
    before polishing. Get it working before you optimize it.
  • Distrust
    all claims for the “one true way”.
  • Design
    for the future because it will be here sooner than you think.

#4:  Syntactic
Stuff: 

  • If a
    constant is tied to a particular class, it should be defined within the
    class.
  • If a
    constant is not tied to a class, it should be tied to an interface.  Don’t implement a class for the
    constant.  You should use the
    constant through the interface name.
  • In
    Java, you can use the javax.print.attribute package and inherit from the
    EnumSyntax class.  Java 5 has native
    support for Enums as does .Net, but safe enumerations that are
    ranged-checked are important.
  • How to
    implement equals()
    • Use
      == to see if you have been passed yourself.
    • Use
      instanceOf to check the lineage of the object.
    • Check
      the equality of each field in your class. 
      If any test fails, return false.
  • Any
    time you override equals(), you should override GetHashCode(). 
    • If
      two objects are equal, they must return the same hash code. 
    • It’s
      not required that two unequal objects return different hash codes, but
      collection performance could suffer.
    • IntelliJ
      is smart enough to generate good equals() and hashCode() methods.  I’ll have to check to see if Resharper
      will do this.

#5:  Orthogonality:
the absence of side-effects.

  • Command/query
    separation:  You should not do two
    things under the guise of one. 
    Don’t calculate something if you name it “get”.
  • For
    example, in a Stack class, if you call “pop”, you remove something just to
    read it.  If an error happens, you’ve
    lost the object.  A more orthogonal
    approach would use a “top” method and “removeTop” method.

#6:  Don’t repeat
yourself.

·        
DRY principle. 
Every piece of information should have one authoritative representation.

·        
If you have an NHibernate mapping, you could
generate it from the database schema (if you have a 1-1 mapping). 

·        
If you want documentation of your system, you
should find a way to generate the documentation from the code.

o       yDoc
is a commercial documentation product that generates UML.

#7:  The Methodology
Rules

·        
Don’t live with broken windows:  If you have a broken window, it indicates
that nobody cares.  If you leave it
there, your source code is fragile.  Your
code will get stronger over time if you are adamant about automated testing and
fixing broken windows.

·        
From Agile Best Practices:

o       YAGNI
– You ain’t gonna need it.  If you aren’t
absolutely sure you need it right now, defer it until later.
o       Embrace
changing requirements by:

·        
Refactoring mercilessly

·        
Set aside time every day to refactor code.

·        
Refactoring is fun, and it is different from
“regular” coding.

·        
Automated testing.

·        
Test coverage gives confidence that you have
changed some code, and you haven’t broken anything.

·        
Testing is a frame of mind, not a tool set.

·        
Who cares if the test was written first or last
as long as the code and test are written close together.

·        
Applications tend to grow from the bottom up
with small, little units of verified code. 
The alternative is writing top down (which is hard).

·        
Generate code coverage reports on your tests.

#8:  Template method
design pattern.

  • If you
    know what the algorithm should look like but don’t know the details, you
    can write the outline and defer the details to child objects.
  • It
    encourages your to define the general order of operations for some process
    in an abstract parent, then implement the details in child classes.
  • This
    works best when the code is small, cohesive, and discrete.
  • You
    should aggressively pull methods up the hierarchy and look for definable
    processes.

#9: Bad Inheritance.

  • Inheritance
    is hard, so use composition instead of inheritance.  Encapsulate the type you were going to
    override and forward calls to it.
  • Inheritance
    is only applicable when the child “is-a” type of the parent in EVERY case.

#10:  Use interfaces
for decoupling

  • Whenever
    possible, define types and member variables as interfaces.
  • If you
    have a class that needs to act as two things, you can implement two
    interfaces.
  • Objects
    are more flexible because they can be treated as either a base class or an
    interface that’s implemented.
  • This
    allows libraries to be written that are not bound to specific classes.

The result of all this is framework code and
configuration.  Framework code is common
code that’s pulled up.  The code with the
details is configuration.  The end result
is a domain specific language that comes out of the APIs that result.

Neal’s final point is that code is the most important
artifact we create.  If you create the
most brilliant piece of software with not documentation and not bugs, you’ll be
a hero.  If you create beautiful
documentation without good software, you won’t be worth anything.