In this post I would like to dig a little bit into philosophical topic, trying to use some analogies between classical engineering disciplines and software development to explain why clean code and automated testing became so important and widely used in software industry.
It is very common today to consider software development to be a craft, not engineering. And while I would agree with this statement to some degree, the argument like “there is very little math in programming, hence it can not be systematic and reliable enough, hence it can not be considered as an engineering discipline” seems to be not really valid. The important insight was given in this amazing article, which simply states that code we write is actually a software design. We used to think that software design is done by very smart guys who draw impressive UML or whatever kind of diagrams. And then monkeys in cubicles sit down and perform actual construction of the code without applying much intelligence to the process. The final product, the machine code after compilation, then shipped to the customer. The agile methodologies boom just destroyed this idea and proved that code in some high-level programming language is actually formal design specification. Formal enough to be taken and without any additional creative thought transformed to the real product, which bring value to the customer.
Now, in classical engineering disciplines, they have similar to an agile process. Design phase goes in iterations and some formal description of future product gets created. This description is further used in the factories and plants, sometimes 100% automated to build final products. To me, it looks like the very close match to software development. The only point, which I think people often miss, is the identification of the final product in software development. I believe it is not a compiled code. Because it is conceptually the same thing as source code, but only translated to the language of worker, so to say. And for interpreted languages there is no such a thing as compilation step. So what is the final product then? Well, it is what brings value to the customer – the process which develops under our design (program). And computing machine is just 100% automated factory.
Ok, but why should you care? You should care because your code is DESIGN SPECIFICATION. And in classical engineering disciplines these specifications are done in the very well defined way with a strong focus on understandability. These specs are media in which design is done. It is used to capture design decisions, to simulate and test future products. These specs are communication media for engineering teams. And by the way, craftsmen never did formal specifications of their designs.
Software engineering is not an exception. The only difference is that we tend to make a mess in our designs. This makes it harder to reflect on systems properties and test them. This is why clean code is essential for establishing software development as an engineering discipline. This is why modern professional developers care a lot about clarity of their designs.
Ok, but what about math? Should we also start intensively use math to become engineers? Well, I don’t think so. I was trained as a classical radio engineer in the university. And I remember very well sitting at the computer with my professor and implementing in BASIC differential equations which described the oscillating circuit. And professor asked if I knew why we were doing it. I just stared at him with surprise in my eyes. The answer was simple, it was much cheaper to analyze characteristics of the circuit we were designing using the mathematical model of the circuit and not the real circuit. I was testing my electric circuit without spending money and time to buy all the components and solder them together (not that it was not fun to build real circuit, I still remember this incomparable feeling of the act of creation). It is simply much cheaper to get feedback on what we have designed before we have built the actual product. But still, mathematical models can be wrong, and testing should ultimately be done to ensure that product does what it is expected to do. Have you ever watched Discovery shows where people test new airplanes? This is just the colossal amount of money. But they have to prove with testing that their airplanes can actually take off, fly and land. No mathematical model can eliminate this design step.
Now, how much does it cost to run the software, i.e. build our products and see if they actually work? It is almost free! Why then should industry spend money on adopting complex formal methods? I can’t see any reason for this and industry seems to be supporting my statement. Analytical proof of correctness of the software seems to be redundant, therefore only empirical methods are left, i.e. testing. However, nice code analyzers are always welcome if they don’t require any additional work to be done on developer’s part. But they will hardly be able to prove that user, for example, can actually save the document in Microsoft Word. If one day this kind of requirement will be possible to describe formally, no doubt, there will be tools wich will transform this requirement to executable programs.
So, the conclusion here is that testing is another ingredient, required for our profession to become engineering.
However, there is a little problem with testing in software. And this problem is in “soft” concept. Software changes very often, it evolves like some organism to meet changing environmental requirements. And without ability to test relatively cheap that software system is still ok after every change, we can’t talk about a systematic approach to software development. Hence, simple testing is not enough. Tests should also be formal and repeatable, i.e. automatic.
Conclusion. Developing software ultimately means designing processes, intended to happen in computing machines. Processes are not material and therefore products, created by software developers, are ideal. Math is not so important because of mentioned idealism and cheapness of building a final product from design spec. This makes a huge difference because all other engineering disciplines build material products. It does not mean, however, that software developers can’t engineer their products, i.e. develop them systematically, rigorously, with repeatable procedures. For this to happen we have to embrace clean coding as well as automated testing – the only practical way to prove software correctness these days. The more systematically we will do this, the closer we will be to software engineering.