Software Development is no Laughing Matter!

47 views
Skip to first unread message

Ian Joyner

unread,
Jan 25, 2024, 7:00:21 AM1/25/24
to Eiffel Users
Here is a response I wrote to a series of joke memes posted at:

https://javascript.plainenglish.io/the-funniest-programming-memes-ever-247dc6daaf40

“Many a true word is spoken in jest”. I hate to intrude on this levity, but there are some serious truths here. Humour is often used when we feel helpless to change anything. Let’s make fun of it instead. But let’s address each of these memes (as far as I can see down to the paid content). Software empowers change. Change is the meaning of the ‘soft’ in ‘software’.

These memes seem to come from the old code-test-crash-hack-until-it-works mentality that comes from people being able to write simple programs very quickly (because programming is powerful), but not understanding what is needed for large-scale complex development. While basic ‘coding’ can be learnt in weeks, true ‘programming’ takes years.

Too many programmers don’t appreciate and can't understand why advanced ‘theoretical-’ or ‘academic-‘ sounding techniques are necessary. They can’t understand the warnings against unstructured features such as gotos and pointers. Large development requires more sophisticated programming and consistency between modules like type checking. These have for too long been dismissed as 'training wheels for beginners' or 'crutches for weak programmers'. People who view advanced techniques in this way are themselves the root of the problems in these memes.

C started this trend of syntactically looking like a structured-programming (SP) language without really understanding SP, just being coding and, not programming, and not embodying the spirit or intent of SP, treating SP as merely fancy syntax. People think they are doing SP by avoiding gotos, only to have them in a different disguised form. True SP is lost.

C++ subsequently adopted classes and inheritance, but only in an arcane syntax, not in a deep semantic sense, or pragmatic sense of supporting how programmers work and avoiding traps. Indeed C++ just magnified the problems of C, without realising the real benefits of OO. C++ just adopted the surface syntax of OO while ignoring the depth, fooling programmers, and especially management that OO had been adopted when really it hadn’t, like people avoiding explicit goto thought and claimed they were doing SP. Deeper understanding and application has always been required.

David Parnas (originator of the importance of software modularity in robust and safe systems) commented that it was unfortunate that many programmers thought they were doing good programming just by using an OO language — the important part was the interfaces between modules, not just arranging things (often haphazardly) into classes. Too many languages, particularly C++, claim to be OO just because of classes and inheritance.

Type systems are another crucial paradigm but Pascal with its early type system was rejected out of ignorance. It is not so much that type systems are absolutely necessary, rather they help avoid mistakes and incompatibilities. C was never about avoiding mistakes and actually built many traps into it. These actually entrap the programmer and projects, locking them into C with its primitive-style programming. Too many people think that learning to avoid the traps in C must be typical of all programming. C was not designed thinking of how programmers work or assisting them much beyond not having to write assembler. That was the basis of C’s popularity — it was still coding without all of that seemingly unnecessary theoretical and ‘academic’ stuff like type checking.

C was an expedience for writing Unix, not a development of great language design. Like C++ with OO, C has lured programmers into thinking they are using a more advanced structured programming language and thus must be writing good software, which as the memes illustrate is more-often-than-not the case. Even writing in a language with deep support at the core for a paradigm like structured programming or OO does not guarantee good software, but the support of C for structured programming or C++ for OO is just on the surface. Support for a paradigm must be deeper than syntax. The fact that bad programmers can write bad software in anything is not a valid excuse for rejecting better techniques. That is just insanity.

Not only did C have simple traps, but also more serious traps like undefined behaviour.

Undefined behaviour means programs must be littered with #define <platform> h #ifdef <platform>, defines themselves being symptomatic of C's primitive and cheap-and-nasty approach to programming, that pushes burden onto tens of thousands of programmers, rather than a few compiler writers handling platform differences where they should be handled.

The differences in platforms should be encoded in a compiler code generator, not a burden pushed on to all programmers to handle, giving added burden against clearly expressing what the software actually does by cluttering the code with #ifdefs. There is a clear choice — handle in the language and compiler, or pass the burden onto programmers to handle. Sadly, C chose the latter, in part because of the limited platforms they did C on and the limited compiler technology of the day. This is really what software is — encoding knowledge in a single location. When put in two or more places, like different systems and programs, conflicts in understanding are more likely to result. In programming we can mostly choose the right way or the quick way. Again in language design, C chose the quick way and the programming industry has been burdened with this ever since.

Despite, or because of C’s deficiencies, the hatchet job disparaging Pascal or anything in that more rational approach to programming and language design began. If knowledge and understanding of Pascal and subsequent languages became established, C would be seen as the substandard language it is.

While more advanced techniques have been developed to avoid the kinds of things in these memes, they have largely been ignored, by the 'we don't need that’, ‘hairy-chested coder’ mentality.

It is time for the industry to take stock, and while we might have a laugh at these memes, there is a more serious aspect to them.
Programmers really need more than a few weeks of 'learning to code' — we need a few years of 'learning to program’. Indeed some of us have spent a lifetime, and still feel we are only partway on that journey.

I will not say there is any 'cure all' or 'silver bullet', but we should not dismiss advanced techniques just because of Fred Brooks' meme or book’s title.

Programmers must learn the fundamental approach behind typing, that of 'Design by Contract’, which is both a theory and a practice. A type itself is a contract on the correct use of a software entity, defining what an entity does, how it may be correctly used, and in which contexts.

Design by Contract (DbC) is wider than type systems. DbC is Test-Driven Design (TDD) done right. DbC puts the tests in the program source, clearly semantically stating what a module (software elements of varying sizes) is expected to do along the interactions with the module (interfaces), whereas TDD tests are external and somewhat black box, DbC knows how a module works being integrated in the module, but effectively encapsulating that behaviour. DbC forms part of a formal specification of a software entity, not just an informal part of an external test. External tests of TDD can only test software along external boundaries, DbC can be used to test the internal workings.

DbC describes both static (compile-time tests) on program logic (not just syntax errors), and dynamic (run-time tests). TDD is only run-time testing. We should detect problems even before we run the software.

Thus meme number 4 is revoked — testing is always present and integrated both as static and dynamic tests (which may easily be disabled once we feel confident the software is correct), not selective or forgotten as is the case with TDD. The earlier problems are detected the cheaper they are to resolve.

Meme 4 is minimised because, like TDD, DbC makes programmers think about what they are doing from the start, not try to retrofit it later, which is what is behind many of these memes. But DbC is done along with the software, not externally to it as with TDD.

Meme 3 on reusability disappears because DbC ensures that modules fit together in the right place. Reusability is enhanced when pieces fit together. As Brad Cox (inventor of Objective-C, the combination of C and Smalltalk) put it: software components or Software ICs — integrated circuits. Pipes (software connectors) go to the right places. David Parnas' comment about the module interfaces being important is addressed in DbC since DbC clearly expresses the purpose and correct use of an interface.

Note that Alan Kay remarked that (in his regretting coining 'OO'), it was not objects or classes that were important, but the interactions (messages he said) between them.

Meme 5 is minimised because programmers are taught good principles and practice with DbC and not left as rookies, but rather trained correctly in the techniques of good programming. Rather than rookies with a few months ‘coding’, we have experienced and knowledgeable programmers. Rather than old-time coders we have people who have thought about programming and thought about how it can be done better.

Bugs due to bad code are minimised and not passed on to the customer or consumer to do the testing for us, or provide the tests missing from TDD. Buggy software creates frustration and loses customers. Rookies are often those who have not learnt to avoid the traps in the bad languages and techniques. We should not laugh at them, but learn the lesson about the fault being in the programming languages and techniques, not in the people who have been consigned to this ‘coding hell’. That is where the blame lies, not with ‘rookies’. Their is too much gaslighting in this industry — rather than blame the poorly-designed languages, blame the victim and make them feel in the wrong. Or have a false sense of security because others fall into the traps laid in languages that should not be there. We must stop inflicting learning the old way around avoidable traps on new programmers as some kind of right-of-passage.

The problems of meme 6 are reduced because DbC will check for inconsistencies between branches, ensuring that all branches remain largely compatible. Again not a 100% guarantee, but 90% is better than the nothing too many projects have. Branch merging has long been seen as a problem. DbC helps avoid those problems. Again, no a guarantee, but better than nothing. All too often, not being 100% is seen as an excuse to do nothing and reject a technique. This contributes to our feeling of helplessness in the truths behind the memes.

Unfortunately, I can’t see beyond meme 6 since I have not paid Medium for access to what are often substandard articles that anyone can publish (not that that applies to this one on programming memes).

How about optimisation? It could be said that DbC sounds like it works against optimisation. No, DbC enhances optimisation by ensuring that different modules work directly together with none of the need for 'gloop' or ‘glue’ code to resolve module incompatibilities. Cleaner programs are more likely to be optimal. Meme 3 shows us that we must take extra paths and pipe to redirect the pipe to where is should have gone. Software is full of these non-optimal deviations that DbC avoids.

While Design by Contract has been around for nearly 40 years, based on Z formal specification by Jean-Raymond Abrial and Hoare Logic, we are still waiting for it in C++. Perhaps C++-24 they say. But again it will be an afterthought in C++, bolted onto the side, ugly, like lipstick on a pig, and not integrated in the ‘soul’ of the language, where it is most useful. It will be more subterfuge that “C++ has DbC, just like the other languages”. This detracts from looking at languages that truly integrate DbC.

Some languages have similarly retrofitted DbC just to fool programmers that they have it and to ‘tick the box’, but without really being at the core. Unfortunately, that reduces important and effective techniques, like structured programming, OOP, and DbC to yet another management fad, where a non-programming manager hears about something and then tries to tell programmers about ‘the latest thing’, which they should now be using. But they have not been taught in how to use it effectively.

The bolted-on form of DbC is just a pattern of using non-semantic asserts, not language integration. That is the measure of primitive facilities — they are things, like preprocessing, that are not really integrated with a language. Patterns and idioms are often to make up for lack of direct language support for important ‘patterns’. We could do DbC in assembler if we wanted, since assembler is the right primitives to do anything, but at far greater effort. Language support is to make it easier to apply a paradigm and take the pain, and thus business cost out of applying it.

Read about DbC in chapters 11 (on DbC) and 12 (on how to recover to make robust software) in: 

Writing correct and reusable software, particularly with DbC is the central aim of the above book. DbC tells us that a pipe connected to an air conditioner is wrong before we get into that situation. Software development and software design are more tightly bound than any other design/build process. Software is far more design as you build. That is once the design is done, we almost have the completed product. We can make changes to software without going all the way ‘back to the drawing board’. Again the ‘soft’ in ‘software’.
Meme number 1 now disappears because rather than a thousand tutorials all around the edges about flaws and traps, programmers have a solid core principle from which much else follows.

Even before we adopt techniques such as DbC, we must get programmers to take the issues (correctness, security, reliability, and robustness, etc) seriously. We must end the attitudes that have been ingrained in programmers for the last 50 years with trite platitudes about ‘programmer freedom’ and needing ‘training wheels for beginners’ which really keep them in slavery so that advanced techniques have not just been missed but wilfully ignored, resulting in the programming profession becoming a joke as in such memes.
Programmers must learn to embed the logic of their programs into the semantics of the program so that absurd situations (as illustrated in these memes) are avoided. Haven’t we had enough of the kinds of issues illustrated in these memes that keep arising because the programming world has consistently ignored the very techniques they should have adopted long ago? This is real 'programming', not just ‘coding' (hacking until it works). The profession must stop and think, and not be swayed by the usual “We have a product to get out of the door to beat the competition to market so they become locked into our product and we make lots of money, while starving the competition who might have spent more time getting it right.”.

Note that while MULTICS was trying to get it right (although using PL/I as a system language was wrong), Unix with C came along. While Apple spent years getting Lisa and then Macintosh right (and Xerox PARC years before Apple caught the ball), IBM came out with their cheap and nasty PC, just a hardware design with no software, even OS, which at the last moment grabbed a Quick and Dirty Operating System (QDOS) which Bill Gates had quickly purchased from Seattle Computer Systems. No wonder this industry is a joke when it comes to quality.

Again, I don’t advocate anything as a 'cure all' or 'silver bullet' but we should not use that thinking as an excuse to not do anything, as in the decades of diatribes against Pascal (while some criticism was justified about the early type system, lack of modules, and being limited in some respects, not the wholesale hatred which was more about any type system, not just Pascal) and later languages.
While we can laugh at such memes, we must also take the underlying messages seriously — and that is that sadly for the last half century, programming has been led down a false path of arrogance in ignoring the theoretical yet eminently practical aspects of software development, where we have people who think they can program after a few weeks of 'coding', yet who lack the breadth of experience, appreciation, and understanding of what it takes to produce large-scale, complex software. It is the old maxim “Those who don’t know history are doomed to repeat it.” — those who lack any depth in programming are doomed to repeat the mistakes. And then there are the programming traps that should not be there, that make things even harder for all of us. Ignorance has been perpetuated with the trite platitudes.

The last 50 years have done the profession of programming a great disservice. Imagine if the aircraft industry had not moved from 1920’s biplanes to Boeing 747s or Concorde by the 1970s because old pilots had said they needed the freedom of the wind through their hair? The lessons of the 1950s and 1960s that were starting to be addressed by the experts who developed such techniques and languages as ALGOL and Pascal (for any of their faults) have been largely ignored and hijacked by the 'do it quickly and cheaply' mentality, constrained by limited 1960s technology, both in hardware capabilities and lack of compiler development knowledge.
We can laugh at these memes and other jokes about the sorry state of programming in 2024, and understand what was trying to be achieved in the 1960s before the 1970s went backwards. Instead of just laughing about it, we can do something about it. Laughter is often used to combat a feeling of helplessness to do anything. We can do something about this, after all, ability to change is the meaning of the ‘soft’ in software. It is time to start taking the jokes seriously!
Reply all
Reply to author
Forward
0 new messages