Anyone can write software, no one can write software | Why coding isn’t Software Engineering

Nir Sagiv
8 min readNov 29, 2019

Coding has become a cornerstone of all activities, while we nearly one fifth into the 21st century it is evident that if you can’t code you can’t be productive, you can’t fully utilize the available horsepower of modern utilities.

Coding is part of the necessary calculations in Excel, to complex multiple sheets pivot tables. Even today mobile phones can “program” shortcuts and define logic based notifications, from reminders once we leave a place (“don’t forget to turn on the security system” or “remember to buy milk on the way home from work”) to other simple tasks like adding every new recipe to a Google Document as a line in an expanse sheet.

In many technology-oriented environments, it becomes even more complicated, as today almost every domain includes coding, from Engineering and Natural Sciences to Humanities.

While most people in technology corporates have some experience with coding, most of them don’t have experience in software engineering, and this small nuance creates much pain for the organization.

An internet disconnection example

For the sake of simplicity, I’ll take a simple problem from my life to explain the difference between the type of coding activities.

My internet keeps on losing connection.
From time to time (on average once a week) my internet connection drops, the only way to restore it is to reset the router.

I would use this problem to explain the four different types of Coding outputs we encounter, and what every one of them means:

  • Coding a Program
  • Coding a Product
  • Coding a System
  • Coding a Product System
The Program evolution diagram
Photo by Kevin Ku on Unsplash

Coding a Program

Coding a Program is the purest coding output; it’s usually something that can be done by one or

two persons, maybe someone in his / her garage, solve a problem and bring value very fast.

Coding a Program is very simple, all the program has to do is to solve a problem, in our earlier example I have a constant disconnection of internet in my house, I’ve coded some Python script that checks for the internet connection, if the test times out the program sends an API call for my router to restart.

Later I’ve added a “crontab” task in my Linux server at home; the script runs once every five minutes and the internet works like a charm!

There is nothing wrong with this kind of program, as it has a particular goal, it can be handled and maintained by the person who wrote it (me), its design for the exact use-case at hand and usually, there is no way to scale it out.

Coding a Product

When I’m talking about a product, I’m relating to a software output that has a more extensive requirements set.

First, this piece of software should be able to run by anybody, not only by an expert (AKA use experience — UX).
Besides, a Product should be testable, repaired, and extended by anyone, not only the genius (me again) who wrote it in the first place.

If I go to the internet hiccups example we’re using, now I need to develop some user interface to this Python script, make sure there are several tests to make sure this program actually works, separate this Python code into logical functions with meaningful variable so once the next developer would have to enhance the program capabilities he would know where to put his changes, have an installer (and uninstaller) and make sure that once something is not working the customer inform of this piece of software could quickly help me help him.

I should even design it in a way that once a new type of router should be supported, no need to run countless hours of backword compatibility test is needed.

We can see that there is some extra effort needed to take a simple Program and make it a Product, usually the rule of thumb should be 3X more time, without adding any additional functionality!

Photo by Clint Adair on Unsplash

Coding a System

Now we might need this small program to work within a system, meaning to be able to interact with other programs, get inputs from other programs and trigger other programs, while still maintaining the original functionality.

For the sake of our previous example, let us say now that I would like to incorporate this simple Internet fixer script that I’ve just coded in a more complex system, this time several programs runs in parallel, each monitoring a different aspect of my internet connection and my new Python script enhance the system.

One program can make sure the DNS servers are reachable (and replace them to a secondary server if the primary one isn’t working well), another program might be some parental control application that measures the amount of time my kids used their devices and block the internet connection after they’ve reached their quota.

Now my program is not running within a system; as such, it should comply with additional requirements for the system to behave.

The first area we should look at is our computing resources; how much memory does it use? How many CPU cycles will it consume? Will it introduce a performance degradation to the overall system?

Another aspect is the interaction between the other programs, my program cannot run once every 5 minutes, as some other program should synchronize everything together.
Maybe I need to have my program continually runs in idle mode and be triggered by a massage from the centralized authority. In that case, I would need to refactor my program to align with the pre-defined protocols of the system my programs run within.

Besides, now that my program runs within a system I need to test it with the full system, and as the system might have several configurations I need to test it with each of the other configurations, moreover, every time one program in the system is updated a full regression needs to happen.

Moreover, what if something in the system doesn’t work?
Now that there are many moving parts within it (many programs), a unique system should be set in place to help debug and find out the program that causes the problem.

Once again, we can see that taking a Program and pushing it into a System introduce more work, the industry-standard talks about 3X effort, without adding more functionality, we can see that as the system we’re integrating our new program is bigger the amount of effort grows as there are

more programs that live in the same environment and needs to be qualified making sure the new program doesn’t break anything.

Photo by Lysander Yuen on Unsplash

Coding Product System

As you probably already see, the last type is both the second and third types together.

This type, the Product System Program is the only Software Output that we reliably deliver to a customer.

When I’m referring to Software Engineering, I’m talking about building a Product System Program.

A system that can be maintained by many people, many times the developers didn’t write the original code, many times the system is too big for one person to understand all of it, and this system is deployable across different environments and configurations.

If to take the effort rule of thumb of the two other types, we would get to a 9X effort to make a simple Program into a Product System Program.

The PDC angle

There are many talented Engineers in PDC, most of them know how to code, usually they can

solve problems very fast since they know the pain areas and the domain (HVP’s) and with a short script, they can reproduce a problem and find the way to solve it.

Those programs have much value as they solve real problems, for us to integrate those programs into our Product System an effort needs to take place.

It is essential to realize that not putting that effort is extremely risky, sending those programs to customers as is ensures that in the future we won’t be able to support those programs, expend them or add features to them.

Installing those programs into a complex system automatically reduces the stability and predictability of the system, the ability to debug the system or even anticipate throughput on it.

Photo by Evan Dennis on Unsplash

So what should we do?

As always the solution includes several paths; the first one is a technical solution; we’re actively working on building a software framework that enables maintaining the integrity of the system with the ability to write fast prototyping.

The second part is education; everyone who codes for production should be aware of the fundamentals of Software Engineering (and knowing how to write code doesn’t mean one know how to Engineer software), what are classes, how to write functions, why we should use explicit types and why automatic testing is so important.

The third is the process; we should all thrive on working together, making sure the software organization understands it’s customer needs (both internal and externals) so we could define the framework according to those, we should discuss the life cycle of those Programs, and plan the timeline for those Programs adaptation into Production grade code.

Interesting, how can I read more!

As always most of the things I know I’ve learned from others, if you want to understand the fundamentals of software development and project management, I would recommend reading the “Mythical Man-Month” book.
This book was first published in 1975 by Fred Brook (born 1931). Fred Brook is a known computer architect, software engineer and computer scientist, he led the development of IBM System/360 (A hardware project) and later OS/360 (the software that came with it). Brook won many awards including the National Medal of Technology in 1985 and the Turing Award in 1999.

Although this book is old, its still very valid, and the ideas that were relevant for massive software development projects (as the IBM OS/360) are still valid today.

--

--

Nir Sagiv

Multiple discipline Ordinary Man | Thoughts about Software are journey snippets @ Applied Materials transforming our software into a Competitive Advantage