[Precise Programming] Philosophy, Principles, Strategies, and Practices

Most of my programming career has been working on large programs, at large companies.

I’m currently working with two programs. One is 66,000 lines long. The other is over two million lines long. Those are typical sizes for the type of projects I work on.

When you have this many lines of code, it’s often difficult to see how everything works together.

Whenever I start working on projects of this size, I end up asking the same type of questions. Where does this piece of code get called from? What does this class do? Why does this code (which doesn’t seem to ever be run) exist? Where is the configuration/setup/mapping file the third-party library uses?

There’s an old programmer’s saying, “Don’t write the code so the computer can understand it. Write your code so the next programmer can understand it.”

When you don’t know how the pieces of code interact, it takes longer to make changes. You’re also much more likely to make a change that will break some other part of the program, because you aren’t aware how, or if, they are connected.

Most programmers will tell you that the first thing they do, when starting work on an existing codebase, is “clean” the code. That cleaning makes the code less ambiguous – more precise.

This is what made me think of “Precise Programming”. I’m trying to group what I’ve learned over the years into something to help reduce these problems – at least, where I can.

 

Here are my thoughts on what it will take to accomplish “Precise Programming”, for the programs I’m writing in C# – although most of the principles should apply to other OOP languages. This list will grow and change over time, as I experiment and see the results.

If you have any thoughts, please leave a comment.

 

Last updated: 17 May 2016

 

Philosophy

  • Programs should do the least-surprising thing possible – for users and other developers.
  • Each piece of code should do exactly what it claims to do – nothing more, nothing less.
  • Programs run longer, and in more places, than expected. Write them in a way so the next programmer will be able to easily modify and maintain them.
    • The intention of the code should be immediately understandable to another programmer.

 

Principles

  • Don’t use “magic” – non-obvious programming techniques. The next programmer should not need to spend any time looking for obscure configuration/mapping/etc. that lets the program run.
  • Clean as you go. After making an addition, or change, to a program, immediately perform refactoring.
  • Find, and fix, problems as quickly as possible. You should never have so many bugs that you need to maintain a bug list.
  • Compiler warnings should be treated the same as errors – and fixed ASAP.

 

Strategies

  • Name everything clearly.
  • Configure your development environment to prevent you from breaking any code quality standards, where possible.
  • Check-in code as often as possible.
  • Run code quality tools on every check-in. Correct any code that does not pass the quality standards.
  • Avoid libraries/tools that need to be installed (with values being added to the GAC, or elsewhere). Prefer tools that only need to have their files copied into solutions.

 

Practices

  • Projects
    • New developers should be able to start working very soon after they pull down the project source code
      • No manual setup/install of third-party libraries/tools/queues/etc.
    • If you change the technique used for one piece of code, implement that for the old code that has the same type of functionality.
    • Create a Constants class, to hold constant values.
  •  Classes
    • Always instantiate objects through factories. This gives a single place to apply default values, use caching, handle changes to third-party libraries (which may have different signatures), etc.
    • Methods should generally not return a value (make them “void”). Communication with other objects should be done by raising events.
    • Place backing variables, properties, constructors, functions (public and private) in a consistent order. Add this order to code formatting tool (like ReSharper).
    • Wrap third-party libraries behind factories or facades, to be able to more easily update the libraries.
  • Properties
    • Backing variables should only be accessed by their setter and getter, even from other methods inside the class. This is to ensure the validation and notifications (run from the setter) are performed.
    • When class A checks multiple properties on class B (or multiple values of a property in class B), class B should probably have that wrapped in an appropriately-named read-only property.
  • Functions
    • Functions and properties should never return “null”. Return an empty list (for example). If you see that your functions are checking for null return values, change the function being called.
  • General code
    • Code should use consistent formatting.
      • Including where in the class you place private variables, constructor(s), public functions, etc.
    • Code should not rely on a naming convention, or file placement, to work properly (due to “magic” service classes).
    • Scope should be as limited as possible.
    • Methods should throw exceptions when receiving invalid parameter values from other code (program-generated).
      • This does not apply to user input. There should be code to clean/prevent that from making it into the internal methods.
    • One-line code within controls statements (ifs, foreachs, etc.) should be wrapped in curly braces.
    • Don’t use “var”, when instantiating variables. Explicitly state the datatype.
    • Properties and methods should be named so comparisons never need to use “not”.
      • Created a wrapper property/function, with a name that allows the comparison to be done without “not”.
    • Don’t use “switch” statements. Either use “composition” or “if…else if” (to avoid missing “break” statements).
    • Error messages should be consistent throughout the program. Don’t have “<Field> is required” in one place, and “<Field> cannot be empty” in another.
  • Data
    • Datetimes should always be stored in UTC

 

Code “smells” to inspect for

  • Look for null parameter checks in functions.

 

C# specific practices

  • XAML windows/controls
    • Include DataContext/DesignInstance of the ViewModel, for IntelliSense.
    • Include Grid.Row and Grid.Column for all elements in a grid.
  • XAML code-behind pages
    • These should almost always be empty.

 

Leave a Reply

Your email address will not be published. Required fields are marked *