“Any darn fool can make something complex; it takes a genius to make something simple.” This quote has been attributed to different people, from Albert Einstein to Pete Seeger. Whatever the origin, I think it really applies to code. When given a task to accomplish developers should all be able to code something that will work. But how will it be understood and maintained in the future? How can you objectively measure something as complex… as complexity?
In my past posts I discussed better ways to assess a program’s complexity than counting lines of code. There are good metrics like the Halstead Metrics that help you in comparing programs on a high level, but they really don’t get to the inside the program. In other words, you can’t see that one part of the program is more complex than another. For that we have to go down a level into the program — to the paragraphs, Procedures or Perform Groups.
Two programs could have the exact same number of lines, operators, and operands, yet be totally different to maintain. Why? It has to do with how they are coded, what they are doing and how the developer chose to implement the logic. The core of complexity is made up of decisions. Think about your own life. Decisions can be difficult, but if they’re made one at a time then they aren’t so bad. But what if they are linked — if a decision leads down one path, which calls for other decisions, which lead to other decisions, and so on and so forth? The overall complexity of the situation grows, and so does the importance of making the right decision at each point. This is the problem we face in code and therefore we need ways to manage the resulting complexity.
One way to manage this would be to just code all of these decisions into one area, be it paragraph, Procedure or module. Grouping them together is easy and it’s the way things are often done. But if you group decisions together, understanding the logic becomes very difficult because you will have to comb through a large section of code to get to the area in question.
It would be easier if you instead attempted to isolate important pieces of logic into separate areas. So, for example, after a main decision, you would branch to different areas and continue this process. Each section should be similar in size and provide balance. Think of it like a Calder Mobile. At each point there is a split with others balancing below it. But if any part gets too large, the balance is gone. This process should make it easier — assuming you have good naming and comments — to quickly locate areas you need to examine. You will have far fewer decisions to understand within those areas.
So, it’s better to break down the decisions into the smallest blocks possible and isolate them. In the end you still have the same number of decisions, but maintenance is far easier. But how to judge the size of these blocks? I’ll introduce a helpful Metric in my next post.