Photo by Kelly Sikkema on Unsplash

Simplifying systems

Milan Brankovic

--

When you start developing, software systems are small and easy to maintain. But they (almost) always grow in time. Human beings hope that they can hold average sized system in their heads at once. This can be only achieved by reducing complexity to simplicity.

A good software engineer will do everything in his power to make what his own work for other programmers (and his future self) simple enough to use and comprehend.

While working on the systems (small or large) we must bear in mind that the purpose of the product is to help people. By following this premise you will share strong connection with your users and will write better software. So whenever a new list of feature request come in, ask yourself how will this feature help users? If it want, or it will help only a small percentage of users you can use this metric to prioritize those features.

Software systems evolve over time. In order not to make them rot, and obsolete when planning about the future we must take the following factors:

  • value: represents the degree to which this change helps anybody anywhere
  • effort
  • maintainability

To calculate cost-effectiveness we can use the following equation

which means: The desirability of a change is directly proportional to the value now plus the future value, and inversely proportional to the effort of implementation now plus the effort of maintenance. This can even be simplified to

as future value and effort of maintenance depend on time. Having this in mind we can conclude that it is more important to reduce the effort of maintenance that to reduce the effort of implementation.

Looking at the future you can not foresee it and thus why the most common and disastrous errors are made because of trying to predict something about the future.

We can not predict the future, but what can we do? As we know that the longer the program exists, the more probable it is that any piece of it will have to be changed. This means that we should focus on present by following these principles:

  • don't write code until you actually need it (You Ain't Gonna Need It)
  • code should be designed on what you know right now
  • be only as generic as it needs right now
  • build system one piece at the time

No human is perfect, and this goes for engineers as well. Good software engineer will introduce 1 defect for every 100 lines, the best engineer will introduce 1 defect for every 1000 lines of code they write. It's inevitable to introduce defect(s) at some point and this probability is proportional to the size of the change which is going to be made. It's important to understand this as defects violate the purpose of product (helping people) and therefore should be avoided. Also by fixing defect(s) we increase the cost of maintainability. Then we can say:

the best design is the one that allows for the most change in the environment with the least change in the software.

In order to minimize the probability of introducing defect(s) we should:

  • never "fix"anything unless it's a problem and you have evidence that shows that the problem really exists (if it ain't broken, don't touch it)
  • ideally one piece of information should exist only once (Don't Repeat Yourself)

If we don't change the system we can not introduce new defects, but if we don't change the system it will become obsolete. So how can we minimize number of defects, but still keep system evolving over time?

The ease of maintenance of any piece of software is proportional to the simplicity of it's individual pieces. We can achieve this by:

  • keeping everything dumb, dumb simple
  • being consistent
  • keeping code readable
  • naming things the proper way
  • commenting only when necessary

Unfortunately people do not naturally build simple systems. Never forget they can be guided to do so!

But what is number one reason why legacy systems are hard to maintain, improve and extend? It's complexity! Complexity can be added in many ways (and these are some of them):

  • complex requirements at the very beginning (so they don't even launch)
  • expanding the purpose of software
  • adding inexperienced programmers with tight time-to-market
  • changing things which do not need to be changed
  • misunderstanding of user needs
  • poor or no design
  • choosing inappropriate/bad technology
  • no proper testing

To handle these complex systems we can either (a) start simplifying things piece by piece (using small steps), or (b) rewrite the whole system. The first one works in all cases except for the case when you have proven that rewriting the old system has less cost than keeping it (and also you have a lot time to spare!).

So, don't forget, the real problem is not the software, technology, requirements, etc. but complexity! Always aim for simple solutions that work now, and strive for easy to use and maintain code.

--

--

No responses yet