Darth Unix

When we formed our teams, we looked for principles that resonated with our ideas of simplicity, modularity and continual testing of ideas by prototyping. We found that simplicity is crucial because complexity breeds chaos and disaster, especially when things go wrong, as they often do.

We found inspiration in the east, where we read about inventors that made products with incredible robustness while under the constraints of lacking financial resources. First, they got the basics working. Next, they dragged their inventions through dirt and mud and dropped them from heights.

Now the team stumbled upon similar principles, the Unix philosophy, which came from Bell labs in the late seventies.

From the Bell system Technical Journal, July-August 1978, one can read about the Guiding Principles, and several maxims have gained currency among the builders of the Unix system to explain and promote its characteristic style.

1. Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".2. Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.3. Design and build software, even operating systems, to be tried early, ideally within weeks. Don't hesitate to throw away clumsy parts and rebuild them.4. Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them.

Of course, we fail to follow these principles, but we try, and they act as our inspiration and aim.

Then of course we stumbled upon the legendary book ‘.

Although Eric condensed the Unix philosophy as of

“Keep it Simple Stupid”

from his book ,

Rule of Modularity: Write simple parts connected by clean interfaces.
Rule of Clarity: Clarity is better than cleverness.
Rule of Composition: Design programs to be connected to other programs.
Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
Rule of Simplicity: Design for simplicity; add complexity only where you must.
Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
Rule of Transparency: Design for visibility to make inspection and debugging easier.
Rule of Robustness: Robustness is the child of transparency and simplicity.
Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
Rule of Least Surprise: In interface design, always do the least surprising thing.
Rule of Silence: When a program has nothing surprising to say, it should say nothing.
Rule of Repair: When you must fail, fail noisily and as soon as possible.
Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
Rule of Diversity: Distrust all claims for “one true way”.
Rule of Extensibility: Design for the future because it will be here sooner than you think.

In our teams, there is a lot of python code written, and from scanning through our code base, I can see that there are traces of both rule of modularity, composition, separation, simplicity and extensibility. What comes in the way are deadlines and, sometimes, difficult missions. Still I see that small modules are reused and built in new combinations to match the evolution of our build systems. Probably a bit later than the rest of the industry, we found that many of the things our teams wrote were to be found in build systems like , so now we are working to use less python and more Bazel. Naturally, python and Bazel blends well.

Code Generation with Matlab Simulink

We also applied many of the Unix principles to the guidelines of our function developers, the engineers who use Matlab and Simulink to draw control diagrams that in turn generate C code. We often hear from programmers who come from other industries, and especially those who love C++, that this method is inferior, but having used both, I can clearly see the benefits of . For large control systems, which are used in vehicles and which can prompt vehicles to exhibit unwanted behavior, software also needs to be well-documented, and in such a task this method is hard to beat.
One reason is that the code generator limits possible constructs. Another is that we only allow certain safe libraries. And finally, we have hundreds of check scripts of the design patterns in Simulink, as well as checks of the generated code. A typical Simulink check pipeline:

- project:
name: repo
check:
jobs:
- buildavoidance-nodeless
- common-gcc_check
- common-pybuild_diff
- common-signal_consistency
- common-cppcheck
- common-checkscript
- common-unittests_shared
- ProjectA-unittests
- common-simdiff
- common-mxray
- common-mxam
- common-mxam_safety
- common-ci_of_ci
- Polyspace code prover

We also use the tool on Simulink models.

The MXRAY complexity report.

This tool uses three primary metrics, McCabe Cyclomatic Complexity, Halstead Complexity, and Incoherence. The primary number is the weighted Halstead volume that fits very well with the design of Simulink. We made a subjective judgment of 500 Simulink models, where we graded their complexity from 1–10. After we scanned the same models with the tool, we got a result very close to our own judgment.

For some tasks, it is better to write the code by using a keyboard, but this may easily be integrated with the Simulink models. In our Software Development kits, which we have put together, we stress that developers who generate code are also responsible for the code. That’s one of the reasons we let these developers push the code to Gerrit and also write unit tests that verifies the compiled code, and not pressing play in a Simulink simulation.

So, the aspects from the Unix philosophy that we stress for Simulink design are:

Rule of Modularity: ‘Write simple parts connected by clean interfaces’
Rule of Simplicity: Design for simplicity; add complexity only where you must.
Rule of Transparency: Design for visibility to make inspection and debugging easier
Rule of Robustness: Robustness is the child of transparency and simplicity.
Rule of Least Surprise: Pay attention to your expected audience.
Rule of Optimization: Prototype before polishing.
Get it working before you optimize it.
Rule of Extensibility: Design for the future, because it will be here sooner than you think.

We also drew parallels to :

Keeping it all tidy

Grow and cultivate trees. First step is to acquire a tree, which can be done by buying a prebonsai (rough material to be pruned and wired) or by using one of several possible cultivation techniques. Very important, however, is to select a tree species that fits your circumstances.

Train and style techniques. Let’s begin with the single most important technique to Bonsai; pruning. Pruning is crucial in keeping trees miniaturized as well as to shape them. The goal is to create a Bonsai that resembles nature as close as possible. Remove branches with unnatural twists and turns. Remove disproportionately thick branches from the top of the tree

Care and maintenance. A crucial part of information about how to grow a Bonsai tree is its maintenance and care.

Converted to Simulink models…

Get a tree. Think about the best flow and use of subsystems before you implement!

Pruning. As the function grows, use subsystems to keep a reasonable size. Create a flow with as few branches and signal lines as possible. Place subsystems so that they feed each other. Small decisions could be kept in subsystems. Try to contain signaling to avoid spaghetti.

Care and maintenance. If the system grows, change of subsystem order might be needed. It could also be of benefit to structure different kind of logic in different subsystems. A good practice is to let each subsystem have a single responsibility; it should do one thing. This in turns leads to good cohesion.

Control flow

Code written by a keyboard

When it comes to code written by a keyboard, we do not have any good methods for analyzing and gating code complexity in our CI system Zuul. The only measurement we have now is Cyclomatic complexity, and that more or less just tells us how hard it will be to test. Although, we do have something in the pipeline, and that is from my colleague and comrade , who has the researched the subject in great detail.

As Eric Steven Raymond states,

you have to be loyal to and pursuit excellence.

You have to come to the conclusion that software design is a craft worth all the intelligence, creativity, and passion you can muster. Otherwise, you will be tricked into the easy path, stereotyped ways of approaching design and implementation; you’ll rush into coding when you should be thinking. Especially if you work in an Agile setting, you might just run in your sprint wheel, and you might carelessly complicate when you should be

relentlessly simplifying

and then you’ll wonder why your code bloats and debugging is so hard.

If someone has already solved a problem once, don’t let pride or politics suck you into solving it a second time rather than re-using.

If any of my colleagues have something better, I will steal it with pride. And of course, we want to automate everything we can, it will save time in the long run.

Programming should be a joyous art, something we appreciate and are passionate about. If we lack this, then maybe we should do something else?

You need to care. You need to play. You need to be willing to explore.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Johannes Foufas

Sr Principal Engineer Sw, drives Zuul CI at Volvo Cars Corporation