Here are 10 things that I think software engineers should think about. Bearing these things in mind will make us all better engineers.

10 Principles of Software Engineering

Overview

Over the years working with teams I've observed a number of things that, when done well, really improve the quality of the software being developed. When I sat down to write this post, these were the things that were top of mind. This is by no means an exhaustive list. Please share your nuggets with me, I'll add them… if they're good :)

Principle #1 - Software Architecture is not Software Design

In broad strokes the architecture of a system defines which components exist, what their functionality should be and how they interact with each other and the outside world. The architecture defines what needs to be built and how it should function, but it does not define how is should be built.

How the actual code should the organized is the software design.

It is common practice in modern software engineering to leave the software design to the engineer. Problems arise when software engineers don't realize that the need to be deliberate about the design of the software they are building and just code away hoping for the best.

Principle #2 - Design is deliberate

Software Design concerns itself with objects and classes, fields and methods, functions, scope and visibility etc etc. In other words, how the solution is realized in code.

Design does not happen subconsciously or organically. I have met a handful of engineers for whom good design appears as they code as if by magic. Just a handful. For most engineers though, deliberate thought and a diagram or sketch are required to achieve anything approaching good consistent software design. Take the time and do the design.

Principle #3 - Embrace the Change

Things change. Requirements change. Software needs to adapt. Embrace the change. Good design is like a superpower because good design adapts easily to change. If your design doesn't adapt, look for ways to improve it. Learn from that. I've experienced some golden moments where a seemingly catastrophic change is quickly and easily implemented. That really validates the design.

Principle #4 - Good naming is the hallmark of great software

Irrespective of the programming language you are using, the natural language naming of classes, variables and methods etc. conveys the purpose of the code. Improper or incorrect names are as important to fix as functional bugs. There are two reasons for this. The first is that the degree to which a code maintains its cohesion depends directly on how accurately that code is named. Cohesion is vital for good design and the better the cohesion the better the code holds up against entropy. The second is that the better the naming the greater the understanding of that code will be when it has to be maintained later. Greater understanding equals lower entropy.

Principle #5 - All software tends toward entropy.

Every time software is altered the resultant quality tends to be lower. There are several reasons for this:

  • Lack of understanding. The engineer doing the maintenance doesn't fully understand the code, or the original engineer no longer remembers.
  • Time pressure. Maintenance often happens on a contracted schedule. Emergency changes and bug fixes often mean less attention to quality.
  • Orthogonal requirements. New feature requirements that don't mesh well with the existing design. The correct decision here is to refactor, but this is seldom done in practice.

Holding the line. Preventing entropy requires deliberate action.

  • Write Unit Tests. I can't emphasize this enough. Unit tests give you the confidence to do what needs to be done. Unit Tests are your only defense against regression. I've worked on teams where fixing one bug introduces two. That is a death spiral.
  • W R I T E -- U N I T -- T E S T S -- ! ! !
  • Refactor, refactor, R E F A C T O R. Spend the time. The longer you delay the refactor the worse the entropy becomes and eventually you'll realize that it may be faster to re-write the software than maintain it. At that point you have failed. Refactor early, when you realize the design is no longer consistent.
  • Rename. This is really a part of refactoring but I've encountered several instances where refactoring doesn't result in the necessary name changes for consistency and cohesion. Make sure you continue to rename to the most applicable name.

Principle #6 - Performance is a Feature

Another way of saying this is "insufficient performance will kill your product". The real problem with performance is that it's very hard to remedy. The key here is to measure early and often. Numbers within the same order or magnitude are generally ok as software can generally be tuned to run up to an order faster. The trouble comes in when you are more than an order of magnitude away. The other problem with performance is that solutions are often fundamental. That is to say the solution may lie in using lower level language components, or an entirely different language altogether. If you are not open to that possibility you are in for hard time.

Principle #7 - R.T.F.M

Seriously. Read the F.ing Manual Already. Modern software engineering is all about frameworks and libraries. Read the documentation. I have lost count of the number of problems I have been asked for assistance with, the heart of which lay at some misunderstanding or misconfiguration of a framework or library. What's worse is that in nearly every case, the problem would have been avoided or easily solved by reading the docs.

Another point to make here is KNOW THE PROGRAMMING LANGUAGE you are using. As more and more solutions require a combination of programming languages, I've seen a decline in the deep knowledge engineers have about a single language. If you are learning a new language be deliberate about it. Buy the book and read it cover to cover. Each language has a few things is set it apart. Understand what those features are and how to use them.

Principle #8 - K.I.S.S

Another oldie but goodie. Keep it Simple, stupid. One of my favorite quotes is "the design is not finished until there is nothing left to remove". Find the simplest solution that solves the problem. Be vigilant about complexity and always be looking for ways to reduce it.

Principle #9 - Don't re-invent the wheel

This is an ever increasing problem in modern software engineering. More and more frameworks and libraries exist in the open source realm that solve many of the common problems we face. It is seldom a good idea to re-invent the wheel. However, on the flip-side not all software is created equal. It is always a good idea to evaluate a piece of software before you include it in your product. Here are some of the criteria I use:

  • Look at the commit history (or non GIT equivalent if it's not on GitHub).
    • Who are the committers. Google them. Who do they work for. That will give you an idea of how well funded the project is and how likely it is that the maintenance and evolution of the project will continue. (I should point out that just because a project is privately developed doesn't mean you shouldn't use it, but be aware that you may end up having to maintain it yourself if you encounter issues)
    • How frequent are the commits. This will tell you whether or not the project is still being actively maintained.
    • How many branches are there. If the project has a decent versioning strategy and stable vs development branches, chances are it's ok.
    • How many times has the project been forked. Have a look at the pull requests, are they fixing bugs or adding features. This is a gut check. It gives you an idea of how popular the project is and also how engaged the community and developers are.
  • Look at the bug list. How many are still open. How responsive are the engineers responsible.
  • Look at the documentation. Is it up to date? (I should point out that all documentation is essentially out of date with respect to the development edge. This is more about stable releases. Look for user guides and quick-start guides etc. API level docs are also good.)
  • Finally google the product itself. Are folks blogging about it? What is the general opinion?

Principle #10 - It's not real until it's in production

There is a sort of reticence that creeps into an engineers mindset when they have been working on a component for a while. The longer the component remains solely in the hands of an engineer, the more reticent they become to put it into production. The trouble is that it's hard to distinguish the "it's not ready" because it's not done from the "it's not ready" because I think I can make it even better. I've heard this referred to as "polishing the marble" and "gold plating". The point here is that it's natural tendency I think.

The only way I've found to completely mitigate this is through the agile practice of continuous deployment. That is to say that tasks completed by the end of the sprint (think 3 week sprint, not 3 month sprint), are deemed production worthy and begin the promotion to production. The next sprint may add features to the next version of that same code and that's fine. This means that engineers are always aware that the code is bound for production in the short term and that issues and imperfections can be ironed out in the next sprint.

(I can talk a length about my views on Agile and the best SDLC practices to employ in an agile shop. That's a topic for another post)

Thanks

Thanks for taking the time to read this. I've tried to keep it as succinct as possible. It truly believe that if more software engineers out there kept these things in mind, we'd see better outcomes. Please let me know what you think, I welcome any and all opinions on the topic.

2013 © Ian Moore