At the beginning of the computer era the system designers came from the world of hardware and it is noticeable. In hardware there are many working elements that can operate in parallel and most times at different rates of operation. This requires hi degree of accuracy in system timing. Chip designers count the number of transistors between two elements to make sure that the Operation Flow is maintained.



The Assembly language defines a set of primitive / native operations. The programming process and software design using Assembly is in direct correspondence with the execution flow. If you want the flow to break then you use the Jump operation explicitly. This is because Assembly was originally designed by hardware developers and was written to accommodate the hardware.



The C language is a procedural language. It was originally created by Assembly programmers (as 'B'). We can still see Assembly type of thinking operations built in the language, for example:

++ is INC

-- is DEC

[A] ? [B] : [C] is equal to:

[A] ;// do operation [A]

JZ ;// if true go to [B]

[C] ;// else do [C]

JMP ;// go to end

[B]

When you are used to working with Assembly you get used to thinking in "test" – "do this if so" – "do this if not". C programmers hardly ever use this.

The C language is a procedural language. It helps us group together sets of operations and also releases us from the need to use Jumps or Go To-s, which can be very simple to track execution flow if you use it correctly but can be easily abused into what was coined as "Spaghetti Code" because of all the lines you need to draw when you try to track the execution flow of an application that was designed incorrectly.



Next evolution, came the language of C++ which is Object Oriented in design. This allows the separation of code modules into discrete software units called a class. Object Oriented programming allows multiple teams of developers to work on the same project very easily. Object Oriented languages can really help the developer manage the code.



The problems that came with Object Oriented programming is that these languages are really designed to help the developer manage the code…

Now it is almost impossible to follow the execution flow. When you want to know what happened in your application when the error message popped up you have to go over all the objects and all the classes that the execution flow went through and many times execution flow travels between several member functions before leaving to another object. Following the execution flow today is almost impossible.



Many times I have seen 'Pure' Object Oriented design producing a code that is a collection of many three-line functions that call each other. Every button click in the application travels through ten or more small functions. You can no longer follow the execution flow by reading the code. This brings two major problems that we face today.



The first problem is that it is no longer possible to detect execution flow bugs with a simple code review. Going over an Assembly code it is very easy to detect simple bugs such as down-casting, potential overflows etc. Reading an object oriented code you can't see the big picture and it is often impossible to review all the small functions that call the one function that you modified.



The second problem with this model is the "Not my fault" syndrome. "I only called a member of another object and it returned FALSE. Don’t ask me why". This is how you get an error that says "Problem with saving the document. Reason is '0x8000745 – unknown', What would you like to do?" What do YOU think I should do?! The programmer got this return value from some object that he is not familiar with and has no idea what this value means so he just pushes that to the higher level. The last level that you can propagate to is the user, and so my mother keeps facing these interesting decisions when she is trying to save a picture.



Object Oriented Modeling was invented to help developers manage the code but had no regard for execution flow. Up till now we used to use step-by-step debugging to see the execution flow. This is no longer relevant when we plan on having multiple threads going over our code. You single step one thread and another completes 5000 loops in the background. If you have multiple threads going over the same function they might all stop on the same breakpoint and you have no way of telling which is which effectively.



Following execution flow today is a terrible problem.



This is the first in a collection of articles that will introduce a new model called the Operation View Model with motivation for using it. This model can define any element in the computer world and it is the next step in software evolution.

Next article will demonstrate how operating systems follow an evolution pattern that is similar to the ones described here.