• Cat litter is more scientific than Computer Science

    Which is more scientific: Computer Science, which is all about numbers and data and exact algorithms, or cat litter, which is all about giving cats a way to poop and pee while reducing the annoyance of their human servants? Seems obvious, right?

    It’s obvious until you understand the practical disaster of creating software as detailed in these posts,

    https://blackliszt.com/2023/04/summary-software-quality-assurance.html

    https://blackliszt.com/2023/04/summary-computer-science.html

    and until you pay careful attention to the information typically found on a box of cat litter and observe how closely the litter does what it’s supposed to do.

    Result: the litter wins by a mile.

    Check out the information on this box of cat litter, a type I often use.

    Back

     

    Let's see in detail how software stands up against cat litter.

    • Problem clearly defined

              The problem solved by a given piece of software can be stated in documents that are huge. And too often vague.

              By contrast, the problem solved by cat litter is clearly defined and already known to everyone who knows how mammals work. There are lots of variations of the details of how cats do what they do; cat litter handles them all.

    • Verifiable promises

              When you buy software or request it to be built, we all experience how hard it is to tell whether we actually got what we were promised. Departments tend to go through extensive “acceptance testing” with new software, or even a new release of existing software, because it’s too often not right.

              With cat litter, you can tell pretty quickly whether the promises are kept. You can see and smell the results.

    • See the results

              Yes you can see the results of software. But there are a remarkable number of invisible results, like databases and files being created and updated, messages being sent and received, other programs being invoked.

    • Consistent results

              Even when software works, it doesn’t work all the time for everyone. Sometimes it goes down totally. Sometimes it just produces bad results – or none at all – for some people under some circumstances. Sometimes you can tell the result is bad but sometimes it seems right but is wrong. Or it crashes.

              People buy new boxes of litter when the old one is used up. They buy it again and again because … it works! All the time, regardless of the variations of the cat’s output.

    Conclusion

    I could go on, but it should be clear by now: cat litter is an exemplary model of science and the associated engineering and production. What should be jokingly called “Computer Science” may be a lot things, but “Science” is not one of them.

  • Summary: Software in Government, Big Business and Big Tech

    This is a summary with links to my posts on the many ways that large organizations including government, big business, big tech and the rest diligently apply modern software procedures as taught in academia and required by professional management; they consistently produce disastrous results in software quality, cost, security and everything else that matters.

    There are of course issues that are common to all these large organizations, for example in cybersecurity.

    https://blackliszt.com/2015/06/systemic-issues-behind-the-cyber-security-disasters-at-opm-citi-anthem-etc.html

    Government

    Government software disasters are government-as-usual, so much so that disasters that wreck lives barely make the news. For example, over 10 million people world-wide enter a government-run lottery for immigration slots that can lead to US citizenship. How hard can picking a bunch of random numbers be? Apparently too hard for the government software people, with the result of horrible consequences for the declared lottery winners whose immigration slots were invalidated.

    https://blackliszt.com/2011/07/software-quality-horror-tales-electronic-diversity-visas.html

    Consider the sets "Excellence" and "Government IT." There is a great deal of evidence that these are non-overlapping sets. I learned there are organizations promoting and celebrating digital government. They hold awards ceremonies. I tried to find out what the winner had done to deserve winning. Surprise, surprise, the link at the organization’s website explaining it all was broken. Pathetic.

    https://blackliszt.com/2015/05/excellence-in-government-it.html

    Even simple things like making Social Security statements available on-line appears to be beyond them — including of course lying about it.

    https://blackliszt.com/2024/03/excellenece-in-government-it-the-social-security-administration-.html

    The NSA (National  Security Agency) has a budget of over $50 Billion and is touted as being the world’s best at cybersecurity. It turns out the only reason we know their super-top-secret budget is because their security was blatantly breached with massive internal data made public.

    https://blackliszt.com/2014/05/bureaucracy-regulation-and-computer-security.html

    Given that this army of highly-paid cyber geniuses can’t protect itself, it’s not surprising that its analysis of a high-visibility security breach may have sounded good to the public, but was in fact entirely fraudulent.

    https://blackliszt.com/2017/01/russia-hacks-dnc-podesta-email-fake-news.html

    What do you do with such a huge budget when you’re unable to do what you’re supposed to do even with your own secrets? You set up a massive program to teach students your excellent methods and hope to train over a million certified experts. I tracked the program from a local community college to the NSA’s own description of its program – which was both broken and insecure!

    https://blackliszt.com/2017/06/government-cyber-security-tops-the-oxymoron-list.html

    Unfortunately, this isn’t just about keeping information safe. Government ineptitude kills people. Instead of taking a quick, simple approach to preventing train crashes:

    https://blackliszt.com/2015/05/an-app-to-prevent-train-crashes-like-amtrak-philadelphia.html

    The government presses on with its super-expensive solution using obsolete technology, which leads to yet more preventable crashes and deaths.

    https://blackliszt.com/2016/10/scandal-hoboken-train-crash.html

    It’s not just big governments. The little government of several islands in the Caribbean managed to create a multi-front disaster using best practices to foist a digital currency system on its innocent citizens.

    https://blackliszt.com/2022/03/dcash-government-cryptocurrency-shows-why-fedcoin-would-be-a-disaster.html

    https://blackliszt.com/2022/03/what-is-behind-the-dcash-central-bank-digital-currency-disaster.html

    The US government continues to pursue a national digital currency of the kind that has already proved to be a disaster in the Caribbean. They do so ignoring the fact that the US Dollar is already largely digital, with extensive software support structures that are in place and working well..

    https://blackliszt.com/2020/12/we-dont-need-fedcoin-we-already-have-a-national-digital-currency.html

    Important things like voting systems are some combination of broken and insecure. I took the trouble to define a simple combination of tech and non-tech to build a modern, secure voting system that was auditable, with operations visible to every voter while keeping what they voted for secret. Will any government institution pay attention, much less implement it? We all know the answer.

    https://blackliszt.com/2025/03/voter-id-and-paper-ballots-dont-prevent-cheating.html

     

    Big Business

    Executives in big business want to succeed and advance, but this can only happen by avoiding risk. The best way to avoid risk is to do what “everyone else” is doing, what the experts say is best. That’s where industry advisory groups come in.

    https://blackliszt.com/2017/05/the-value-of-computer-industry-advisory-groups.html

    Giant advisory firms counsel their customers on how to make the best decisions. Getting your customers to like you is high on the list. Carefully crafted words are of supreme importance to such large organizations. Actions that match? Not so much.

    https://blackliszt.com/2016/07/gartner-group-big-company-customer-service.html

    A giant health insurance company “lost” the personal information of "tens of millions" of its members sometime in 2014; they're not sure how many, whose records were "lost," or when it happened. The details are an astounding illustration of big-corporate IT incompetence.

    https://blackliszt.com/2015/02/the-anthem-of-cyber-insecurity.html

    I soon found out that my information had indeed been stolen. The company’s response to the theft was right in line with their letting it happen.

    https://blackliszt.com/2015/02/my-anthem-account-was-hacked.html

    What company doesn't want to be part of the digital revolution and have an app? If you're a major health insurance company, why wouldn't you replace old-fashioned insurance cards with something always up-to-date that comes on an app? Here’s what ensued when one of the industry giants tried.

    https://blackliszt.com/2021/02/why-cant-big-companies-build-or-even-buy-sofware-that-works.html

    I've covered many big organization face-plants. The awfulness encompasses a broad range of consumer-dissing inconvenience, Here’s a case of some software that "works" but puts customer inconvenience front and center.

    https://blackliszt.com/2021/03/why-cant-big-companies-build-software-that-works.html

    Here’s a case of a giant company software issue that is low on the “it matters” scale, and high on the “a smart high school student could have done it better” scale. It’s the kind of issue that leads one to wonder whether we’d all be better off if they refused to hire any more people with college degrees for any job, and in particular, management.

    https://blackliszt.com/2021/05/anthem-needs-my-feedback-reveals-deep-problems.html

    Big Tech

    Whether the software is a cool social app, an academic website or a real business, there is a common theme: the software is poorly designed and, even worse, it just breaks. You might think the cool internet apps like Facebook and Twitter are an exception, but they’re not.

    https://blackliszt.com/2012/01/internet-software-quality-horror-shows.html

    How can you innovate? Did the leaders of the current big tech companies benefit from training in innovation? Once they became large, have the big guys like Google demonstrated excellence in innovation? Uhh, sorry, the facts indicate otherwise.

    https://blackliszt.com/2016/05/organizing-for-successful-innovation-recent-history.html

    The widely-accepted logic is: Facebook is wildly successful; FB is built on software; therefore, FB software must be excellent. I should hire people from FB to help me build excellent software! The history and facts support neither the logic nor the conclusion.

    https://blackliszt.com/2014/12/fb.html

    I looked at FB’s mobile app when it had over 700 million people using it. Over 20 million people had written reviews, more than 6 million of which were 3 stars or less. A random sample of those reviews yielded juicy results.

    https://blackliszt.com/2014/11/facebooks-software-quality.html

    The difference between image and reality at FB is astounding. Here is an interview and a recent book that should lead any ambitious young company to avoid hiring people from there.

    https://blackliszt.com/2017/03/software-giants-image-and-reality-facebook.html

    Large organizations have trouble building software. This has been true since the dawn of software history, and shows no signs of changing. The decades-long, rolling disaster of Microsoft Windows is a great example of this.

    https://blackliszt.com/2015/08/large-organization-software-fails-the-case-of-microsoft-windows.html

    Microsoft illustrated multiple issues relating to digital ownership in a case I dug into. Among other things they attempted to require use of their own pathetic browser.

    https://blackliszt.com/2014/05/giant-software-bureaucracies.html

    There are big problems with software quality. The social apps in particular have decided it's embarrassing. But instead of actually, you know, fixing the problems, they seem to have decided to mask the problems! Twitter is a great example of this disease.

    https://blackliszt.com/2013/05/twitter-software-quality-stinks.html

    I did detailed studies on Twitter and found that they do indeed produce provably bad search results.

    https://blackliszt.com/2013/05/twitter-software-quality-an-oxymoron.html

    People write and talk about what's "trending on Twitter" as though the trend meant something. It doesn't. It's based on deeply flawed Twitter search software that gives random, widely varying results.

    https://blackliszt.com/2013/05/the-bogus-basis-of-trending-on-twitter.html

    Twitter fired boatloads of software engineers in 2022 leading some to predict that software disaster will ensue. But then, most people don’t know much about software and don’t realize what a disaster Twitter software has been for years.

    https://blackliszt.com/2022/11/twitter-can-improve-software-quality-by-losing-most-of-its-engineers.html

    Then there is Apple, the high-prestige computer company making expensive devices. In 2016, terrorists killed a bunch of people in California. Law enforcement and the FBI worked hard to find out what happened and who else might have been involved. This required looking in the government-issued iPhones used by the killers. What happened? Apple did its best to protect the criminals. Here are the highlights.

    https://blackliszt.com/2016/03/the-apple-fbi-fiasco.html

    And here are the details:

    https://blackliszt.com/2016/03/apple-can-help-fight-crime-while-maintaining-privacy.html

    https://blackliszt.com/2016/02/apples-cancer-prevention-strategy.html

    https://blackliszt.com/2016/02/apples-approach-to-privacy-terrorists-and-criminals.html

    I reviewed a book about government security on Amazon. The author was impressive and had loads of experience. Many of the reviews were positive, with a few pointing to obvious bias. I wrote a review that pointed to the positive aspects, but also mentioned some of the bias. The review disappeared. I interacted with Amazon, and was told that suppressing the review was a mistake. It appeared again. Then it disappeared. I tried to write a review and was told I've been banned!

    https://blackliszt.com/2023/03/early-evidence-of-criticism-suppression-by-intelligence-agencies-.html

    Yelp isn’t as big as the industry giants, but it’s pretty big. A random plunge into their system demonstrates the same kind of slick surface with rotten underpinnings as their larger brethren.

    https://blackliszt.com/2021/05/yelp-big-tech-incompetent-corrupt.html

    Conclusion

    There is a better way! The winning methods aren’t even new – they’re proven in practice by small groups that need to win. See:

    https://blackliszt.com/2023/07/summary-software-innovation.html

    https://blackliszt.com/2023/07/summary-wartime-software-to-win-the-war.html

     

  • Summary: Software Experts

    This is a summary with links to my posts on software experts. For medical experts see this:

    https://blackliszt.com/2023/08/summary-the-medical-industrial-complex.html

    The hype about experts is so extreme, it’s important to take a bit of time mocking it. After all, experts confirm that experts are super-smart and never make mistakes!

    https://blackliszt.com/2021/04/experts-are-super-smart.html

    Medical doctors considered blood-letting to be a standard part of medical practice until well into the 1800's. They continued to weaken and kill patients with this destructive "therapy," even as the evidence against it piled high.

    The vast majority of software experts strongly resemble medical doctors from those earlier times. The evidence is overwhelming that the "cures" they promote make things worse, but since all the software doctors give nearly the same horrible advice, things continue.

    https://blackliszt.com/2019/02/what-software-experts-think-about-blood-letting.html

    The Wannacrypt ransomware attack caused havoc world-wide in major corporations and government institutions. It's a textbook lesson in a number of subjects including the worthlessness of most Experts and the rank illiteracy of otherwise highly educated journalists about computing.

    https://blackliszt.com/2017/05/the-ransomware-hack-attack-lessons-from-the-experts.html

    Governments are filled with Experts, particularly on important subjects such as security. In 2017 the US government declared that the Russian government hacked important US entities. The official report was filled with impressive-sounding evidence that demonstrated the incompetence and/or duplicity of the agencies that issued it. The majority of the US press simply echoed the nonsense.

    https://blackliszt.com/2017/01/russia-hacks-dnc-podesta-email-fake-news.html

    Big Data is one of those subjects that is widely touted but opaque to most people. It’s a classic forum for Experts to have their statements taken as infallible. A famous expert in Big Data and elections made an error in a recent election that clearly illustrates typical Expert behavior of seeking an outcome instead of the truth.

    https://blackliszt.com/2017/04/big-datas-big-face-plant.html

    Experts and anointed authorities of various kinds, both academic and commercial, have been the front lines of resistance to innovation for centuries. They are the firewall keeping rogue ideas outside the environments they oversee, protecting them from bad influences that their naïve but innocent charges might inadvertently adopt.

    https://blackliszt.com/2020/05/experts-vs-innovation-new-book.html

    Groups like Gartner sell expertise as a service. Go to them if you want to know the best thing to do! The real value of such groups is to help executives avoid risk and avoid blame when things go wrong. Innovation? Industry-acknowledged experts are not the way to go.

    https://blackliszt.com/2017/05/the-value-of-computer-industry-advisory-groups.html

    If you're doing something new and want to do it right, it's natural to seek the help of someone who's been there and done that. If you want to do the thing in an innovative way, that's all the more reason to seek expert help. The trouble is, however useless experts are in general, they’re worse when it comes to innovation. The history of manned flight is a good example.

    https://blackliszt.com/2016/07/innovation-and-experts.html

     

  • Summary: Regulations

    This is a summary with links to my posts on regulations.

    Regulations are supposed to make things better. Most of the time regulations make things worse by preventing innovation, increasing costs and failing to achieve the goals for which they were created. The negative impact of regulations, whether government or corporate, is greatly magnified in software and technology.

    The reason why our ever-growing number of regulations fail to protect us is simple. In the vast majority of cases, they spell out, often in great detail, how to accomplish the goal, instead of plainly and simply defining the goal and leaving it up to the person or company regulated to figure out how to get it done.

    https://blackliszt.com/2011/12/regulations-goals-or-directions.html

    Regulations that define a goal enable innovators to find new ways to accomplish the goal, whether it’s a better medical device, computer security, whatever.

    Another way to think about effective regulations is the criminal law, which regulates behavior. There aren’t ever-growing mountains of regulations telling you how to avoid murdering someone, just a simple statement that murder is something you must not do.

    https://blackliszt.com/2012/03/lets-criminalize-our-regulations.html

    Regulations are front-and-center in the bureaucracy-driven battle to prevent innovation. Regulations are ever-growing mountains of words written by lawyers and bureaucrats. The current federal regulations have more than 100 times the number of words than the collected works of Shakespeare.

    https://blackliszt.com/2016/09/innovation-the-barriers.html

    Regulations and standards can be good; without standard steering wheels and brake pedals, no one would be able to drive a rental car. Software is different. The misguided effort to impose standards and regulations on software development has played a key role in the nonstop cybersecurity disasters and software failures that most organizations try to minimize and ignore.

    https://blackliszt.com/2021/11/the-destructive-impact-of-software-standards-and-regulations.html

    Medical device regulations increase costs and prevent innovation. The FDA device regulations provide an excellent example, declaring in massive detail how exactly to achieve quality in classic how-type method. The what-type (criminal version) would simply declare that the device must perform its declared function, accurately and well.

    https://blackliszt.com/2016/12/regulations-that-enable-innovation.html

    A similar story plays out in the field of medical imaging. The essential devices could be vastly improved if the regulators got out of the way.

    https://blackliszt.com/2023/01/how-to-reduce-the-cost-of-medical-imaging-and-pacs.html

    The bureaucrats who write regulations for software are ignorant of software. It’s literally invisible to them! Their understanding, such as it is, tends to be based on false metaphors and is wildly inappropriate. They end up requiring expensive, obsolete methods for building software that no sensible company would use.

    The current mountains of regulations should be replaced by something like “We don’t care how you build your software, but it’s your responsibility to assure that the software performs its stated job without fail. If the software has errors that cause medical harm, you are responsible for the damage it causes, and you may be barred from supplying software to the medical market in the future.”

    https://blackliszt.com/2020/05/heres-how-the-fda-can-reduce-medical-device-costs-while-improving-healthcare.html

    Regulation is also about important things like making trains safe so that, even when something goes wrong, you don’t have a crash that kills people. That’s one the government has been all over. They devised a system called PTC (positive train control) to prevent crashes. The cost to implement it was tens of billions of dollars and took many years. Years after it was mandated there was a crash that killed people and injured hundreds.

    https://blackliszt.com/2015/05/an-app-to-prevent-train-crashes-like-amtrak-philadelphia.html

    The crash in Philadelphia wasn't a one-off. The problem is that PTC is built on computing technology that belongs in a museum, not supposedly protecting our lives.

    https://blackliszt.com/2016/10/scandal-hoboken-train-crash.html

    The technology exists to enable a more effective, inexpensive system to be built using modern technology. But of course the regulators ignore it.

    Whenever the government wants to step in to improve a company’s software, beware. When has such a move ever had a positive impact on anything, much less the stated goal of the regulation?

    https://blackliszt.com/2015/04/the-government-wants-to-help-ubers-software-quality.html

    There has been a recurring furor about the unfairness of the internet. According to the critics, regulators at the FCC should step in and impose “net neutrality” to make service fairer for everyone. In fact, what few problems there are have been caused by regulation. And where regulation has been imposed elsewhere, government-mandated severe censorship has quickly followed.

    https://blackliszt.com/2014/11/net-neutrality-it-aint-broke-dont-fix-it.html

    It’s not just the government. Big bureaucracies to “control and improve” software emerge in giant companies of all kinds. Even in a software company, the in-house regulators can impose insanity. Here’s a case involving Microsoft and digital goods.

    https://blackliszt.com/2014/05/giant-software-bureaucracies.html

    Regulations have an outsized role in causing the on-going disaster of computer security. See these for examples and explanations:

    https://blackliszt.com/2017/05/security-regulations-vs-security.html

    https://blackliszt.com/2014/05/bureaucracy-regulation-and-computer-security.html

    https://blackliszt.com/2013/07/cyber-security-standards-are-ineffective-against-insiders-like-edward-snowden.html

    For more about security and how regulations make things worse, here is the summary post.

    https://blackliszt.com/2023/05/summary-the-ongoing-problem-of-computer-security.html

  • Moving towards Occamal software

    Someday, there will be tools that actively help you build occamal software. I imagine that the tools will resemble a modern IDE, but will have assists, wizards, visual representations and other methods of helping you see actual and potential commonalities. In addition, there will be common components, both part of the development environment and part of the execution environment, which will make building occamal software easy and natural. Until such tools and components exist, the work and imagination of the developer will have to fill the gap. Remembering that we live in the real world, our goal is not to build software that is perfectly occamal; software that is nearly occamal would be wonderful, and software that is much more occamal than today’s software would be a big improvement.

    A good way to think about occamality is the elimination of redundancy. It may be useful to put redundancy into categories that vary by blatancy. So we can identify:

    • Simple redundancy

    Simple redundancy is really, really blatant redundancy. There’s not much excuse for it, although some programming environments are shockingly encouraging of it. A great deal of the Y2K problem was due, sadly enough, to simple redundancy. Most of the relevant programs were written before databases were in common use, and there was in any case no native support for the “date” data type in the programming environments used; in the vast majority of cases, no one bothered to take the simple steps required to create the then-equivalent of a date data type. During the seventies, instead of eliminating simple redundancy, people spent their time engaged in fierce ideological arguments about whether “structured” programming represented an advance in program quality and programmer productivity or whether it was just a bunch of hoo-hah. The extent and depth of the Y2K problem told us the answer.

    Simple redundancy is normally cured by replacing the redundant instances with references to a definition of whatever it is that they have in common.

    • Complex redundancy

    Complex redundancy takes some real effort and energy to eliminate, though often not a great deal. Complex redundancy involves redundancy over multiple programming environments or some other issue that raises it above the simple. For example, you may display dates on screens and store dates in databases. Is there a truly single place where you define what you know about “date” in general and each date in particular, for both environments, including temporary variables and parameters? If not, you have a case of complex redundancy. Dates are relatively easy these days, because most systems provide some sort of native support for them. So take something more application-specific, which is unlikely to be predefined, like account number, part number, order number or something like that and ask the same questions.

    Complex redundancy is normally cured by shared definitions, but those definitions need to be created and maintained outside of the individual programming environments, and generated into them as needed.

    • Redundancy due to incidental differences

    There are many cases where there are true differences between potentially redundant items, but they are distinctions that don’t really “make a difference.” This kind of incidental difference frequently comes out of “over-determination,” for example, specifying that a certain field should be at this exact X and Y position, when what you really mean is “under” some other field.

    • Redundancy due to over-refinement

    Sometimes differences that are potentially “incidental” spring from definite user requirements. Typical sources of such requirements are highly experienced and sophisticated users, experts in a field, who know how it’s best to do things. They know, for example, that at step 4 of a certain process, they have always wanted the screen to be different in this or that way, to remove or add these buttons or fields, or do something else that makes that screen different from the others. It’s something they feel strongly about. It expresses their knowledge, experience and judgment. Rejecting the requirement can be taken by such people as ignoring their experience, denying their knowledge and deprecating their judgment. In other words, it’s bad. It may be a great idea to incorporate the suggestion – or it may be yet another distinction that definitely has a cost from the beginning to the end of the software project, and in the end makes no real difference. From the point of view of Occamality, the bar has to be set very high for such things.

    • Redundancy due to external software

    Another prime place for complex redundancy to show its ugly face is in interfaces. Many interfaces require you to do the same thing over and over and over again; they give you no choice. If there is no way to centralize this and eliminate the repetition (see next section), you’re stuck in a highly non-Occamal situation, and there may be little you can about it.

    • Redundancy imposed by the programming environment

    Some programming methods, tools, languages and environments naturally lend themselves to redundancy more than others. A good, simple example is the “polish” convention of naming variables, in which the variable name includes its type, for example instead of just naming a variable IDENTIFIER, you would name it IDENTIFIER-INT to indicate that it’s an integer. The convention came out of a real problem – someone would apply an operation to a variable that was inappropriate for its type; wouldn’t it be a nice idea if the name of the variable itself reminded you of the type so you wouldn’t make such mistakes? Yes, of course, but then if you need to change the variable’s type, either its name misleads you or you have to find every instance of it and change it. While well-intended, it’s non-Occamal.

    Once you begin to think about simple things like variable naming, you begin to wonder why in most programming environments, the name of a variable has any significance at all? Why can’t you go to the single place where the variable is defined, and change anything at all about it – including its name?

    The exercise is pretty simple. Anyplace you see repetition of any kind, you have to ask yourself, when I make a change, do I have to find all the places and make the change? The answer is probably yes, and it’s not good.

    • Redundancy to which abstraction can be applied

    If you’re just looking at code, redundancies may not spring out at you – in fact, at the level of the code, there may not be redundancies. But that doesn’t mean your code is Occamal! Sometimes there are common ideas that are expressed with great diversity in the code – or so you realize once you grasp the relevant abstraction. In such cases, it is typical that the people who understood the original problem and the people who wrote the code thought they were dealing with many independent things, and the abstraction that unified them simply never occurred to them.

    A good example of this is a collections system I worked on. This was a huge body of code that was used to automate the work of hundreds or thousands of people in call centers whose job was to call people who owed money to an institution, for example a credit card company, and get them to pay. The code had a wide variety of concepts implemented in that were specific to the collections industry. I came into the situation with a broad background in multiple workflow-type applications, and quickly recognized that collections was 95% call-center-oriented workflow, with a little customization and a few specific features for collections.

    It wasn’t obvious when looking at the code, but if you started with the basic workflow constructs (workstep, queue, conditional routing, etc.) and took it from there, you ended up with a much more compact and easily extensible application. The original application was simply a “collections” application with some parameters; changing anything required finding the relevant places in the code and making the changes. The new application implemented a core set of workflow abstractions, and hardly ever needed to change. It also had a set of easily editable tables that expressed the current state of the workflow, which enabled almost anything to be changed. Finally, it had a small collection of application fragments that were truly specific to collections, things like the “promise to pay” function.

  • Occamality: the problem with layers, components and objects

    Modern software orthodoxy endorses the notion of collections of code that are separated by high walls. Object-oriented thinking codifies the supposed virtue of data hiding, and keeping all the code that works on a particular block of data (a class) behind a wall. Everyone seems to like the idea of components; people will talk in terms of assembling applications out of component building blocks (when has this ever happened except in seminar rooms?). Finally layers or tiers are supposed to introduce discipline to an application. The idea is you have the user interface (top) tier; then you have the application or business logic layer; and finally you have the database layer. Frequently, these are designed and built by separate groups, each a specialist in its domain – do you really want those superficial, flashy, image-obsessed UI people messing around with your transaction datado you??? Of course not. But you also don’t want the groups to “hold each other up,” so the idea of having the layers be strictly separated so the UI people can do their thing without being held up by the others.

    This is the theory. Lots of people practice it, or at least say they do. If you’ve never experienced anything else, it makes sense. Just the other day I met a software company chief scientist, a PhD in something or other, who explained to me that they were converting some scripts from PERL to java because java was a “real” language, and the scripting languages – all of them! – were not. I didn’t get a real explanation of why this was so; he took it as self-evident to all educated and reasonable people that it was, and by questioning it I really tried his patience, since I was apparently uneducated and unreasonable…

    Components, layers, microservices and objects can be good things in limited circumstances, but it’s really, really important to see that if you accept that the prime measure of goodness of a piece of software is occamality for the reasons already discussed, in general, components, objects and layers reduce occamality to the extent they are applied.

    The core problem with these things is that they result in multiple definitions of what amounts to the same data. The theory actually encourages this. Take a simple data element such as “account number.” In any program involving accounts, this piece of data will be all over the place. If you’ve got layers, it will be in all of them, because surely it will appear on screens, business logic and the database. If you’ve got objects, it will be in the interfaces and internal implementation of many of them – think, for example, of “account master” and “transaction.” If you think you’re being clever and have built yourself a message passing architecture, it will be in the message definitions – lots of them.

    Naturally, you assume and hope that the definition of account number doesn’t change, and in most cases it won’t, in which case the wild redundancy won’t hurt you much. But problems come most often from things you didn’t think about – what happens if there’s a merger, and suddenly there are a whole set of accounts you’d like to bring into your software, and the new account number definitions are totally incompatible. What if they’re bigger and there’s no way to cram them into the existing scheme? You desperately cast around for translation schemes, but in the end you accept the inevitable: you’re hosed.

    Now think about this: what if there was a central place where everything you know about account number was defined? Suppose the central place had everything that all the layers needed, for example label for the UI and foreign key relationships for the database. You could go to this single place and take care of most of the account number issues. I assume the program isn’t perfectly Occamal, and there are a few other places you have to go for everything to work. So what? You’re way better off than you otherwise would be.

    The painful, anti-orthodox but blindly obvious conclusion is this:

    • Each “layer” you put into your software increases its complexity and time to construct, and increases the time and risk to make changes to it.
    • The more you use classes and other forms of object-orientation in your code, the more redundancy you introduce, and thus the harder you make your code to construct and change.
      • You may think – before you’ve had lots of experience – that the data hiding of classes increases the “componentization” of your code, and thus makes it easier to change without trouble. Sadly, your thinking on this subject needs revision. Parameters and calls weave your objects together and make them do useful things, and the greater their interaction, the greater the redundancy.

    There will always be people who love components, objects and the rest, just like there will always be people who insist on having half a dozen gin-on-the-rocks before supper to whet their appetites. Words don't work. Logic is irrelevant. They should stay in university or wallow around in some giant software bureaucracy where they'll have plenty of company.

  • Achieving Occamality through definitions: case study

    Quite a few years ago I had the problem of creating a product that would help printers create estimates for potential printing jobs. We had one of the early micro-computers at our disposal, and the only programming tool that was available for it was a macro assembler. We had to get the product out in a ridiculously short period of time, and were very limited in the amount of memory we could use.

    We got together and realized that we had a fairly simple problem. The ultimate goal was to create printed estimates. Each estimate was calculated based on a combination of data that was unique to the job (the size of the paper, the number of colors, the number of copies, the type of paper, etc.) and data that was common to most jobs, but could be changed at will (the amount to charge for different kinds of paper, press setup and per-copy charges, etc.).We also had to save estimates and create new versions with changed parameters.

    Here’s what we did. We broke the whole problem down into seven overlapping problem domains. We created a set of macros for each domain. The parameters of each macro contained attributes relevant to the domain. When assembled, each macro would deposit coded data in memory – no instructions. For example, we had a set of macros for input, another for printed estimates, and another for the core variables relevant to estimating. Macros could refer to other macros, so we could eliminate redundancy and keep the memory requirements as small as possible.

    Each parameter in a macro had to correspond to or do something, so we definitely wrote code, but the code we wrote was highly abstract and was roughly proportional to the extent of the macro parameter definitions. When we added a new macro or a parameter to an existing macro, we would add or modify a couple line of assembler code.

    The actual functionality of the program was created by a small amount of code that rarely needed to be touched and was pretty easy to write and debug, and a relatively larger amount of macro calls that deposited meta-data in memory. The instructions walked through the meta-data and created the behavior the user saw. We spent time at the beginning understanding the nature of the problem, defining macros and writing code. As the project went on, we spent less time with code and definitions and more time with writing and modifying macro calls. As time went on, the users got more and more stuff, and we were able to change what they didn’t like quickly and without introducing further errors or side effects.

    We lost a good deal of time because we picked a computer that was too early in its lifecycle. It had hardware errors, and the macro assembler that was so important to us was buggy. The operating system was primitive, and we even had to write our own file system. In assembler. With a flakey machine and a buggy macro pre-processor.

    The main competitor at the time had a system they sold for roughly $25,000. Ours was faster, easier to use, had far more functions, and could be sold at great margins for $10,000. The project was taken on by me and three totally awesome geeks. We delivered the product on the date that was fixed at the start of the project, a date that based on nothing except when it would be nice to have the product. It proved to be nearly bug-free when delivered to customers; one customer found one bug after a couple of months, and I was able to fix it in an hour. Time from start to finish: ten weeks.

  • Achieving Occamality: What not How

    I don’t think I can improve on Chris Date’s formulation of the issue. His basic point is that most computer programs solve problems by taking an imperative approach, telling the computer how to accomplish a given task. He argues strongly in favor of a declarative approach, telling the computer what needs to be accomplished, and having a core set of application-independent functions that accomplish the goal in an optimal way.

    Date’s favorite domain is databases. His approach works for databases by writing a program that knows about schemas (tables and columns), data (rows) and SQL statements (Insert, Select, etc.). If you can fit your problem of representing (the schema) and manipulating (the SQL) your data in the way databases expect, and an amazingly wide variety of problems can be represented in this way, then you get to define, load manipulate and access your data without writing any code at all. Since the one body of DBMS code ends up solving a huge number of problems, this approach is highly Occamal.

    There are other well-know examples. Spreadsheets are a good one. If you’ve got a spreadsheet-type problem, you can get your needs met quickly and well. You can even write formulas and small program to perform custom calculations.

    While databases and spreadsheets are widely understood “horizontal” applications, the approach is applicable to nearly any domain. In fact we often take an approach of this kind when writing applications anyway! If you look at a body of code, there will probably be some code that actually performs an application-specific function that users, for example, would think is meaningful to them. Then there’s all the “other” code that you had to write to enable you to deliver the application value. What’s unusual is for programmers to go “all the way,” and make a clean separation between domain-related abstract functions and application-specific declarations.

    The notion of "what" not "how" is a far-reaching one. For example, most of criminal law is "what" you're not supposed to do — don't kill anyone! The law doesn't spell out "how" you're supposed to avoid killing — just don't do it! By contrast, most regulations are written as "how" type rules. For example, instead of just saying "the medical device as to work correctly," typical "how" type regulations spell out in gruesome detail how you must accomplish this; and better ways are not allowed!. See this for more detail.

  • Achieving Occamality through definitions

    This is a deep subject, and challenges the way many programmers think. It is rooted in the most fundamental assumptions about the way computers work and the way we program them. In my experience, the ideas first strike people as being simple, obvious, and uninteresting. They seem irrelevant to anything important, and even seem like far-out crank talk.

    One way to approach this is to imagine that you stop a computer and examine its memory, byte by byte. At one level, it’s all data. By definition, what’s stored in a computer’s memory is data. But in practical terms, every single byte falls into one of two categories: (1) “plain” data, and (2) instructions. Instructions are placed or loaded into a computer’s memory like any other data, but unlike plain data, the computer can be “pointed” to a starting address and told to start executing the data that is there, and good things will result if the data conform to the rules for instructions.

    Achieving Occamality through definitions essentially amounts to dividing the computer memory into three categories: in addition to instructions and “plain” data, you add “meta-data.” If you wrote a program with just data and instructions, you would have a certain amount of space devoted to each. If you write a program using meta-data, the data stays pretty much the same, but the space devoted to instructions typically shrinks by a great deal, and you have a good deal of space devoted to meta-data.

    It is important to note that the meta-data should not be in the form of tokens, and while the instructions in some sense “interpret” the meta-data, the meta-data should not primarily be a directive, imperative program.

    In practical reality, what you do is create a descriptive, declarative language that is as close as possible to the problem domain as possible. There should be a minimum of translation between the “natural” way of thinking about the problem and the way the problem is expressed in the language. A good example is a navigation system as described here – the meta-data describes the map in natural terms. If you understand language concepts at all, there is probably a one-to-one relation between elements on a visual map and elements in the map description language.

    Of course, even a highly declarative approach has a directive aspect to it. My intention here is to emphasize what is usually ignored, not to present an either/or. For example, while a program that gives directions mostly consists of the map meta-data, the direction-generator itself can usually be built in a partly imperative and partly declarative fashion, and needs some plain old parameters, things like whether to avoid toll roads or interstate highways.

    This is not a left-field approach to programming. In fact, every method of programming computers, with the arguable exception of “raw” assembler language, starts with a “model” of the kind of program you are going to write, and a choice of how to think about that program.

    One of the earliest approaches to rising above raw assembler was the language FORTRAN, short for “formula translator,” derived from the fact that its creators were scientists and engineers who wanted to put their mathematical formulas into the machine for solution.

    The business programmers who wanted to use the machine for common business record-keeping functions didn’t find FORTRAN particularly helpful. So COBOL, an acronym for Common Business-Oriented Language got invented.

    While it’s reasonable to think about FORTRAN, COBOL and the various languages that succeeded them in terms of language, and this has often been done, it is also reasonable to think: When I sit down with language X, what kind of problem does it help (or hurt) me to think about? How much “translation” is required from the natural terms of thinking about the problem and the language? Do the very terms of the language talk about things I think about? If not, you probably have an opportunity to create a definition domain in which to express your problem, and write a much shorter program than you would otherwise need to write to get the job done.

    I’m happy to say that the approach I advocate here is very close to what many people call “model-based” programming. It is ironic that this is so hard to describe, instead of just being mainstream common sense. When you think about a body of code that solves a problem, it is normally possible to code each abstract function that the code performs many times exactly once, and then reduce things it does uniquely to a set of meta-data. Most programmers are pretty comfortable taking this approach when defining the schema for a database-style problem. The model-based approach is really little more than taking the concept of a database schema and greatly generalizing it.

  • Case Study: Replacing metadata with fashionable software

    A VC firm I worked for made a (sadly, in retrospect) passive, non-controlling investment in an emerging PLM company that was all over model-based, declarative  development. They didn’t use silly, made-up names like “Occamal” to describe what they did, but they were fully self-conscious of the power of meta-data, and used it fully. The CTO chose Microsoft as the target technology stack, and ran into the fact that most programmers who specialize in this stack found the meta-data approach to be a foreign one. He overcame the problem by getting his programming done by a group of mathematically-oriented programmers in Kiev, encountering a phenomenon I have encountered many times, namely, that people who think mathematically find it natural to think in the abstractions demanded by Occamality.

    This company, AA, had both the problems and the achievements many companies have at their early stage. It had accomplished amazing things in a remarkably short period of time with a small team. It had created a distinctive product that could be customized with an order of magnitude less effort than competing products. It had some really happy customers.

    AA also had some unhappy customers. It had made some promises it could not keep, and its code had some really embarrassing failures in the field. It had gotten speed and innovation pretty well down, but quality and reliability remained works-in-progress.

    AA accepted a major investment from a couple of brand-name venture capital firms. Each of the firms had name-brand partners on the investment. They surveyed the customers, and discovered the quality problems. So, naturally, you would think they focused on fixing the quality problems, making sure to keep the overall approach that was the key to the company’s value. Makes sense, yes? What else would experienced software-industry investors do? Well, they could do what they actually did – which was hire a big-name CEO, who brought in his own VP Engineering, who glanced at the product, decided it was no good because it wasn’t written in a proper language, viz. java, and put the existing product “on ice” while his huge new team re-wrote everything in industrial-strength java, which of course, as everyone knows, is a language so magical that all you need to do is write in it and what results is fast, bug-free, infinitely scalable programs.

    I came in at this point and raised a strong protest. I defended the model-driven vision and most of its execution. I pleaded for spending the new money to fix what was broken – the quality and release process – and for continuing to nurture the goose that was already laying gold nuggets and clearly gearing up to laying golden eggs. It was like I was from Mars, and not the advanced-civilization Mars of science fiction, but a hick Mars in which the most visionary thinkers could hope there was a Stone Age in their future. They tolerated my presence with curled lip and up-turned nose, and went back to whatever they thought they were doing before I intruded on them.

    A year and a half later, all the money was spent, the re-write of the application was “nearly” ready to ship (a status it maintained for an amazingly long period of time), some of the programmers were found to have played with visual basic at home, which accounted for the fact that the magic that normally makes java bug-free had been compromised by exposure to impurities. Worst of all, customers were telling the CEO that they wouldn’t upgrade to the new version even if it were perfect, because it lacked the easy adaptability of the original, model-based application. The CEO did what any sensible, experienced executive would have done under the circumstances – blamed the founder for his flawed product and market vision, flaws so profound that even a total re-write was unable to cure them, and sold himself into another job, where they were glad to land such a seasoned executive who had such practical, down-to-earth judgment.

    The investors, left to pick up the pieces, had no choice but to return control to the founder/CTO, who, amazingly, had stuck around while the new team was spewing all the money into the garbage dump while dumping on his vision and execution. He hired a VP Engineering, a Russian with many years of hands-on US-based software experience, who fully appreciated the vision, and was able to get the newly re-hired, largely Slavic software team on board with making quality an equal partner with speed and innovation. The quality problems got fixed, customers were re-enchanted with the product, and AA enjoyed a second chance at success. (A few inessential facts have been changed to protect the guilty.)

    Occamality is the best possible software architecture, but it ranges from unknown to miles beyond left field. Successful, experienced software professionals are highly likely to dismiss it out of hand in favor of whatever the cool thing is at the moment. To be successful with Occamality, not only do the engineers need to understand it but the executive management team has to understand that the approach is the keystone of the company's technical advantage over the competition.

  • Understanding Occam-optimality practically

    Here are some basic thoughts to help understand Occam’s razor for software as it is applied in practice:

    • Build only the software you need to build in order to be successful.
    • With rare exceptions, shorter programs are better than longer programs. The goal of programming should be to produce the minimum lines of code in order to accomplish the job.
    • Always keep the “parts count” of your program in mind, and make it your goal to keep the number of “unique parts” to a minimum, with each “thought” expressed exactly once, with everything that “uses” that thought generated from the primary expression of the thought. See this for a practical example.
    • The best days are ones that reduce the total number of lines of code while increasing the functionality of the program. A day spent doing nothing but writing new code may very well be a day that that reduces the Occamality of your program, so that every line of code adds to the later burden of testing, documenting, learning, using, maintaining and ultimately changing the program, thus making it worse than it needed to be in nearly every respect.
    • In situations where there are multiple paths to a software goal, pick the shortest one that involves the least amount of work. Don’t plan for future change; if you write the shortest possible program, future change will be optimally prepared.
    • Ignore common practices if they produce redundancy, and thus violate the razor. For example, multi-tier design frequently results in huge redundancy of data definitions. A multi-tier execution environment is fine, so long as the tiers are generated from and share common definitions, so that the program at the source code level is Occam-optimal.
    • Frequently, software is complex because the requirements are needlessly extensive and complex. Reducing and/or standardizing the requirements is a key part of Occamal software.
    • Apply Occamal principles to the whole process involving the software, from requirements through to training and support. Cases that seem marginal when looking at the software in isolation often become clear when taken in full context.
    • Copy, use, ignore or emulate everything that is not uniquely required to be successful
    • Avoid over-determination, i.e., putting in things that sound good or say more than you mean to say. For example, there is frequently no mechanism to deliver the results of error checks in a database to the people or programs that need them, and they are therefore useless. Again, some people use screen design programs that specify design elements in far more detail than they really mean, therefore saying too much.

    A great deal could be written about this. For an explanation of the "post-hoc design" approach to Occamality, see this. It's a way of speeding the way to a goal.

  • Understanding Occam-optimality technically

    I am not aware of a set of terms I can use to make a technically clear definition of “Occam optimality” for software, so I’ll just re-use some existing ones. I suspect there’s an exact, more mathematical way to do this. I’m hoping someone will pull it off. My goal here is to express the most basic relevant concepts in rough terms.

    By “program” I mean the entire source text that is required to build the executable program. If the program uses a DBMS, the schema definition is part of the program. If there are “include” files or resource files, they are part of the program. If the program is a multi-tier one with an ASP GUI, a component-based application and a database layer with stored procedures, it’s all part of the program. If there is information that is part of the program that is not immediately available as text, then for these purposes we convert it to text. While we normally think of these things as being in totally separate categories, for these purposes, we will construct a single source text that has everything required to build the program.

    Here’s a tricky, vague but essential definition. Without this definition, an occamal program would be just a version of the original compressed by mechanical means, kind of like a compiler optimizer. The “intention” of a program is its true goals, without technical specification or constraint. The “expression” of a program is a “program” as defined above, i.e., completely determined by its text. A single program intention can have a very large number of possible expressions. The purpose of the normal program design process is, at the very early stages, to clarify the intention, but most of the process is designed to narrow down among all possible expressions to get close to a narrow range of possible expressions. The final determination of program expression is, of course, made by the coders.

    The effort of creating Occamality comes during the process of turning “intention” into “expression.” Of all the evaluation criteria that have been used to drive and evaluate this process, and there have been many, the occamal criterion says: express only what has been intended (don’t over-determine), and express what has been intended in the least possible number of “semantic units” possible, with no redundancy among them.

    I use the awkward phrase “semantic unit” to indicate a programmer’s thought, and to avoid getting caught up in one language vs. another, the number of characters involved in the keywords and syntax, comments, the length of labels and variable names, etc. A semantic unit is any combination of code, data and meta-data that is required to express a thought. Semantic units can be primary, composite, and have any number of connections and relationships among them. Good definition and use of connections and relationships are how redundancy is eliminated, along with careful attention to avoid “distinctions without a difference” of substance.

    Semantic units can have “primary” information in them and/or “reference” information. “Primary” information in a semantic unit is an actual definition or program statement, for example a data type or a conditional expression. “Reference” information is a reference to one or more other semantic units. For example, you would define that a date is a month, day, and year, with these data types, lengths, labels, compute rules, etc. This would all be “primary” information about date. When you defined “birth date,” its most important characteristic would be the “reference” information that it is a type of date. A semantic unit could easily contain a mixture of primary and reference information. For example, “birth date” would have as primary information its unique label and the fact that it is a separate piece of information; everything else about “birth date” would be a reference to “date.” The reference should be a single reference to the “date” semantic unit.

    References, as defined in this broad sense, are the key to creating occamal programs. Every reference is something that could have been given a separate expression, which might have been literally identical, but more likely would have had the same intention but differ in trivial detail as expressed. In the example of the Y2K problem, each reference to a central date definition replaces a separate definition of date. Without references, all the separate instances of date would have to be found and changed; with references to a single central definition, all that needs to change is the central definition, and the references cause the change to be rippled to all uses of date.

    A “program” is Occam-optimal when it has the minimum possible number of “semantic units” in its expression, and when there is no redundancy among the semantic units, while still fairly expressing the original intention of the program.

    Obviously, this only scratches the surface of the technical side of Occam-optimality. I hope it’s enough to convey the general idea.

  • Classifications of Software Programs

    Anyone who has programmed for a while knows that all code is not alike. There are important broad categories of code. I wish there were a generally agreed to categorization, but there doesn’t seem to be. Many years ago, there were these categories (from lesser to greater in terms of perceived expertise and prestige):

    • Operator (your hands actually touched a physical computer!) – low status!
    • Applications programmer (many variations here, from business analyst to debugging and maintenance). And even they are not all the same! While I was working in a COBOL shop, I discovered that there is an intense, sharp difference among COBOL programmers:
      • Batch COBOL. There is no direct human interaction here.
      • Interactive COBOL, the kind that paints the infamous “green screens.”
      • Guess which is more prestigious?
    • Systems programmer (these got the problems when the application programmers were stumped)
    • Computer vendor employee (these people wrote the operating systems, compilers, and other tools that systems programmers “maintained = got blamed for” at user sites)

    When I worked at a computer vendor, there were clear distinctions among those who were concerned with:

    • The operating system kernel (and then there are the drivers, the people who deal with them have to suffer from hardware dependencies)
    • The operating system utilities
    • Compilers
    • Database systems (“simple” file systems fell under quasi-core OS; add a serious index or mention “b-tree” and you moved here)
    • Networks

    These distinctions were necessary and real. The coding disciplines, received knowledge, experience, and so on were different enough for these things that people could really be good at one and not at another. Unlike in the dreaded and despised world of end users, there was no clear hierarchy. While the kernel guys felt themselves at the center of the world, as in some sense they were, there was no denying the fact that compilers involved all sorts of special knowledge, and this got really annoying once OS’s started getting written in languages requiring compilers.

    I suspect there are other reality-based classifications of code. But for these purposes, I would like to break all programming into some categories that cut across these and others I have heard of:

    • True algorithms
    • Abstract realizations of generic functions
    • Application and device specific definitions and logic

    Algorithms

    Algorithms are the blocks of code studied so well in Knuth’s multi-volume series, The Art of Computer Programming. They are things like sorting, searching, managing lists, etc. There are lots of other sources, but he focuses on the key factors for code that implements algorithms. In spite of the impression that may be given by his many volumes, there are a relatively small number of algorithms, and it is important that a relatively small number of people like Knuth study them intensely, understand everything about them, and make them available (I’ll gladly pay!) in standard, canonic, guaranteed implementations. Most of the metrics in this paper are not relevant to algorithms.

    Why is this? Because, for most algorithms, we continue to value the amount of space they use and the amount of time they take to execute. In increasing numbers of business applications, sub-optimal algorithms could be used without ill effect, at least in some places. But if an optimal algorithm is available, why not use it? Why make life complicated (not to mention error-prone) by introducing two classes of algorithms, the optimal ones and the good-enough ones – what’s to gain?

    The life and analysis of algorithms in practice is by no means complete. There are important advances to be made. But most algorithms are advanced by someone solving a previously unsolved problem (like Dijkstra and the shortest path) or by taking advantage of a newly altered constraint (disk memory is now much cheaper than it used to be, therefore we can reasonably do X, which was a terrible idea in the days of expensive disk). Because of their different goals (minimization of space and time within constraints), algorithms play by different rules than other programs.

    Abstract generic functions

    Abstract generic functions implement things useful to many applications, but not specific to any one of them. Application “frameworks” are a mother lode of such functions. The Rails framework in Ruby is a reasonable modern example.

    Any programmer who has written a variety of programs knows what I’m talking about here, and has his own candidates for inclusion. This has its origins in the FORTRAN FORMAT statement from Paleolithic times. Major categories of software products have emerged that started as application-specific code, moved on to be abstract generic functions, and then finally hardened into products. CRM and Content Management systems are recent examples. However, software products as currently typically designed and delivered aren’t nearly as useful or flexible as unified collections of abstract generic functions. The closest thing we have is application frameworks.

    Application-specific definitions and logic

    This is where everything else goes. This is the code and meta-data that makes your application your application, different from others.

    Even this can and should be broken into layers of generality! For example, there should be one place for the common aspects of your UI design, and one place that defines what is unique to each particular interface.

    The important thing is that, to the largest extent possible, you are mostly selecting and marshaling the general mechanisms available, and making them particular to the problem at hand.

    Of course, your problem may have some highly unique elements. These elements may involve writing some serious code. The code may resemble in depth and complexity that of abstract generic functions. But you’d better just write it to solve the problem at hand, and leave generalization to another day.

  • Occam-optimality applies to all stages of the software life cycle

    It’s natural that Occam-optimality is mostly focused on software. But it applies to everything from requirements to architecture and design, QA and testing, documentation, support and the endless round of changes software tends to have.

    Requirements occamality

    Are Occamal principles just being applied by the programmers who code up the application? If they are, that’s good, but there are steps in the software cycle before the programmers start their work, and if those steps are conducted without Occamality in mind, even if the programmers program a perfectly Occamal program, there will end up being many more lines of code than there could have been. This is easiest to see in the requirements process. Suppose one group writes up requirements for an on-line credit card application and another group writes up requirements for an on-line application for a term loan. The requirements are likely to be similar because the same kind of data needs to be collected in both cases. But what if one group takes a very matter-of-fact approach, while the other emphasizes fancy graphics, visuals and user interaction? Once those requirements come to the programming group, unless that group is amazingly perceptive and aggressive, the two sets of requirements will be treated as wholly unrelated projects. In other words, business as usual.

    Imagine, on the other hand, that the people thinking about requirements are familiar with Occamality and want to apply it. Rather than starting from scratch, they may look for places where the data they need is already being collected – maybe this new project is an opportunity to unify some existing code, and bring it into the Occamal world. In any case, the two groups will decide that they’re really one group with a couple of minor differences between the two applications, and they’ll also realize that the styles of user interaction will change over time, so they’ll take some effort to separate that out from the actual data gathering. The net effect is likely to be a set of requirements that are “pre-occamized,” that should not take much transforming for the software group to implement in an Occamal way.

    If software requirements aren’t Occam-optimal, the software may be occamal in some abstract way, given the requirements, but the requirements themselves may demand a solution that feels like there are all sorts of special widgets and do-hickey’s that could just as well be dispensed with. In other words, Occamality is best achieved if it is a conscious goal from the very start of the requirements process to the end.

    Here are some reasons why it’s important to think Occamally in the requirements:

    • Redundant requirements or ones with trivial variations normally result in needless redundancy in all the following steps.
    • A set of requirements that are similar in principle but different in detail are frequently over-defined and over-refined, creating work that delivers no value.
    • People who create requirements frequently know a great deal about their subject and have thought about it long and hard – and the more they know and think, the more extensive their requirements are likely to be, which is often a problem.

    Software requirements people frequently resemble the washing machine designers I have described who optimize what they do over a very narrow domain. The result is screens and functions that are highly customized to the job for which they’re intended. Every bit of customization adds that much more to what has to be programmed, tested, documented, taught, learned, used and maintained. This is typically a very large cost for an assumed benefit that often isn’t even there, because people find uniform programs easier to learn and use.

    The consequences of applying Occamality as broadly as possible in the requirements will roll down the line of testing, documentation, roll-out, training and support, saving time and money each step of the way.

    Software scope occamality

    If you look at 100 lines of code, you may be able to find some redundancy, but probably not too much. If you look at 1,000 lines, 10,000 lines or 100,000 lines, there are likely to be whole gobs of redundancy.

    When you cross the line from one officially-designated “program” to another, you greatly increase the odds of finding redundancy. Within a single program or project, there is only so much you’re like to find. But particularly within a single business, the same things come up over and over, and get solved over and over again, each time in slightly different ways.

    Things begin to get interesting when you cross traditional software boundaries, like from user interface to application programming to network to database. In each case, there are frequently specialists who do things in their own way. If, as is likely, they have caught the “object orientation” bug, they each attempt to create their own little worlds of nicely designed classes/objects. But when you look at the project as a whole, and you think of something like “account number,” think of the number of times and places and ways that concept has been defined. Even within one of those domains, like the application, an account number data element will be defined as part of each class, and will appear every time account number crosses to or from the database, and again every time account number crosses to or from the user interface. You’ll find that “account number” is all over the place! If you have any question about this, just try to change the data type, label and error checking for it, and see how many places you have to touch to make it work.

    Software architecture Occamality

    Occamal thinking is crucial in the architecture and design of the software:

    • Achieving Occamality frequently involves introducing a strong but appropriate amount of abstraction into the program design. Simply translating requirements with minimal abstraction into objects, schema designs, etc. typically leads to huge amounts of redundancy.
    • If you just focus on the text of the code, you may find little redundancy. But you may also be able to achieve substantial code reductions by taking a whole different approach.

    Software QA Occamality

    The usual approach to QA is highly redundant and un-optimal. When QA automation is normally performed, it is highly redundant, and leads to a system that doesn’t have better quality but is even harder to change. Typical script-based automation ends up having the effect of copying variables already present in the program in a different environment (the QA one), and creating logic that reflects and is derived from the base program. This approach to quality automation clearly reduces the quality of the overall program, and certainly reduces its occamality of the overall software effort The ideal approach is highly automated, fully supports occamal software, and indeed is occamal itself. See this for more details.

    Later stage Occamality

    Post-coding software steps benefit indirectly from smaller code and less redundancy, but in addition, Occamal thinking can benefit them directly.

    • Occamal thinking applies to documentation and help text. The arguments about redundancy making documentation more difficult and error-prone to change apply fully.
    • Let’s not forget the users! Chances are excellent that additional code is the direct result of input from some users, but most users will suffer as a result. Every concept, field and command you eliminate is one more thing users don’t need to worry their little heads about.

    It is important to focus on Occamality in the code. Extending it to encompass the entire life cycle of software is what delivers big benefits. Post-hoc design as described here is a practical approach to accomplish Occamality in waves, without going too crazy trying to do everything perfectly.

  • Occamality and other design principles

    People use and defend the use of all sorts of methods and tools for building software. The number and range of methods and tools is overwhelming. Is Occam optimality yet another entrant to be added to the already-too-long list? No. I hope that the notion of Occam optimality will be understood to be independent of all those methods and principles, and will provide a way to both improve each of them and, in some cases, select among them.

    If the notion of Occam-optimality is correct, it stands above and cuts across all methods of building software. It is a principle that enables you to take two efforts to build a program in the same environment and tools, and say objectively which is better.

    It is certainly true that some tools and methods make it easier to achieve Occam-optimality than others. But it is important to understand that Occam-optimality is not primarily about judging tools and methods – it is a notion of optimality that can be applied given any selection of tools and methods. Programs can be written in assembler language (assuming there’s a good macro pre-processor) that are Occam-optimal, and in fact it is easy to understand the concept in that environment, since everything is laid bare.

    If most current ways of thinking about programs are like algebra, then the analysis and understanding of Occam-optimality is like calculus. Just as calculus doesn’t replace or criticize algebra but is built on it and extends it, so is Occamal analysis built on existing methods and tools of program construction. Just as calculus provides tools that didn’t exist before, like methods for calculating the area under a curve or the zero or minima of a curve, so does occamal analysis enable us to understand what “optimal” really means for most programs, and gives us guidelines and a way of thinking to enable us to construct programs that approach occamality.

    Unlike the myriad algebra-like methods of program design and construction, an occamal program that meets the business intentions is also very likely to be optimal in terms of all the other goals that business people have: it will be as efficient as possible to define, build, test, document, deploy, learn and support. Most important, it will be possible to modify and enhance it more quickly, safely and inexpensively than any other kind of program. To the extent that the program fails to meet important expectations on any other grounds, e.g. performance, availability or attractiveness, a program that is occamal lends itself to alteration to meet those expectations better than a program which is sub-occamal.

    Once this criterion is understood and accepted, our tools and methods will evolve rapidly to achieve the maximum possible productivity in software design, construction, support and evolution.

    Focusing on the occamality of programs is a way of focusing on what we most care about in software. It doesn’t eliminate our other concerns – we still care that programs perform reasonably, that databases avoid corrupting data, etc. But an amazing number of those other concerns will be taken care of by-the-way if our programs are occamal, and if they’re not, we know that occamal programs are almost by definition the easiest to change to address any need or fill any gap.

    I worked with a company having horrible problems with the administrative workstation of their storage product. It took a long time to load and many seconds to respond to reasonable-seeming requests. Its user interface was inconsistent and it took a very long time to update to reflect changes and new features in the underlying product of which it was a part. Looking under the covers, it turns out there were more than 200,000 lines of what turned out to be java code, and it was really hard to say what useful function large chunks of it were performing. Java was selected because the people thought it was modern, object-oriented, and would let them build re-useable components and other good things. Then they just started writing code, and here we were.

    There were lots of arguments, pro and con, about whether java was any good, all of which were beside the point – wrong discussion. After a great deal of struggle, the whole thing was gutted and replaced with less than 20,000 lines of code and definitions. The people doing the work did not concentrate on performance, changeability, or other architectural concerns – their main goal was to make it small. When they were done, and they did it quickly, they had a complete replacement, a consistent user interface, and it magically became really fast and easy to change!

  • Occamality in Software History

    Occamal concepts have naturally emerged in software efforts from nearly the beginning of software, and limited formulations of Occamal concepts have been promoted and valued in software. The purpose of this section is to identify those early expressions for what they are; they show the widespread, ever-springing nature of the desire to come to some principle that will yield optimal programs.

    Software tools

    One of the earliest pure-software efforts, the work to build the early language FORTRAN, was clearly a step in an Occamal direction. By creating a machine-independent language in the first place, programmers could concentrate on expressing their programs in a single language, FORTRAN, instead of the multiple machine languages that came to exist. Since FORTRAN is closer to the problem domain of most scientific programming, it usually takes fewer statements to express a program in FORTRAN than in assembly language; therefore, writing in FORTRAN eliminates redundancy and is thus better in Occamal terms. The relationship between the statements of the language and the machine language are all centralized in one place, the compiler. The compiler’s run-time library was just as important in this respect – it provided a set of commonly used functions that only needed to be written once, and then used whenever needed. In the early days of FORTRAN, for example, machines typically did not provide native support for floating point operations. The programmer could write his floating-point formulas and calculations without thinking about the machine, knowing that if the machine his program eventually ran on had no support for floating point, the compiler would generate the right calls and the run-time library would do the work.

    All computer languages take programs in an Occamal direction. Just as FORTRAN abstracted and centralized the floating point operations commonly needed in scientific computing, so did COBOL abstract and centralize processing records of data and the BCD arithmetic needed for financial calculations.

    Similarly, the concept of subroutine and shared subroutine libraries arose very early. One of the important functions performed by early software societies (IBM’s SHARE, the ACM and IEEE) was to collect, refine and standardize libraries of functions widely used by groups of people. Early software companies owed their existence to the time and money it took to build major functions, and built a business on selling many copies of software that was expensive to build, and less expensive for the user to buy than build for himself.

    The use of macros is clearly driven by Occamal goals. The idea and motivation of a macro is simple: when there are repeating examples of a string in the text of your program that you suspect you may want to change in the future, you define the text in a macro and use the macro instead of the text itself. When the need for a change arises, you go to the single macro definition, change it, and you’re good to go, regardless of how extensively the macro is used.

    The concepts of inheritance, templates and component re-use are clearly Occamal in nature. The idea is you write the common parts of a function in a master class or template, and then sub-class or apply the template to handle special cases or variations. You have the master class or template which gives you the single place to go to make changes, while benefiting from only needing to spell out the variation in each particular application. Using these things tends to reduce the number of lines of code and reduce the redundancy, and is therefore Occamal.

    Software applications

    Occamality can be clearly seen in the evolution of software products.

    Over time, software efforts in a particular field naturally tend to the Occamal, model-based ideal, because such bodies of code are the easiest to maintain and enhance, while providing maximum flexibility to their users. Early attempts at building Customer Relationship Management (CRM) systems, for example, tended to be bodies of code written in some supposedly easy-to-change 4GL. Every CRM system needs customization. When one of these early CRM systems was installed, the source code would be opened up, programmers would hack away, and sometimes an application vaguely appropriate to the customer’s needs would emerge stumbling from the dust. The awfulness of this approach quickly became evident as customers found that upgrading to the vendor’s latest release meant re-entering the coding war zone and having to fight a battle on two fronts, i.e., their customizations of the old release and the vendor’s “improvements” to the old release in the form of the “upgrade.”

    The vendors who survived this nightmare were the ones who, through natural selection and the survival of the fittest, minimized the damage to their customers through the installation and customization process, not unlike the way parasites evolve to avoid killing their hosts. Invariably, this meant increasing degrees of Occamality (not “perfect” Occamality, mind you, just “increasing degrees” of Occamality), nearly always expressed as a more model and template-based approached to application definition.

    Engineering product management systems, usually called PLM systems, are an example of a set of software that has long-since evolved to be more Occamal than not, simply because engineering products and processes are so highly individualized that one of the main functions of modern PLM products is to make it easy to express product and process definitions without requiring modification of the source code of the product.

    Here is further explanation of the evolution towards increasing application in software applications.

    These examples make it clear that Occamality is a thread that weaves through the software industry and underlies many of its developments, although the people who created and promoted the developments generally did not think of them in these terms.

     

  • Occamality in Databases

    The accepted practice of database schema design is a good application of Occamal principles. In fact, in a broad sense, Occam optimality takes the concepts accepted in schema design and applies them to programs and the software lifecycle as a whole.

    Someone at a bank would write a system for automating checking accounts. Naturally, the account information would include the name and address of the person who owns the account. Some else would write a system for automating savings accounts. Naturally, the account information would be essentially the same; it may be the same because someone knew all about the checking system and copied it, or it might be the same because of “convergent evolution.” The account holder moves, and somehow tells the bank. The person at the bank has to look everywhere the person’s address might be stored and change it there. They might miss a place, or they may enter something incorrectly. This places a burden on the bank, makes extra work, is a source of errors, and may lead to customer dissatisfaction. It’s far better to have a single place where a person is identified at the bank, and where the things we know about that person (name, address, phone number, etc.) are stored. In the database world, this is the concept of “normalization,” which essentially means store each piece of unique data exactly once.

    The database world also has the concept of “reference” in a couple of ways. If the person actually sets up a checking account, the checking account system needs the account information for the customer. This is done by identifying each account by a unique identifier, known as a “primary key.” The primary key is associated with the master copy of the account-holder’s information. Then, in each place where the customer uses a bank service, for example a checking account, a “foreign key” to the account information is placed. This is actually a copy of the primary key. So if you are customer 123, your primary key is 123, and the number 123 is also made the foreign key for your savings account, your checking account, etc. Calling it a “foreign key” says that it’s a reference to the one place where the information is stored, and not the master copy itself.

    The database also uses references to eliminate redundancy in data types. When you need multiple fields that have to be distinct but actually represent the same kind of data, you define the type information once in something called a “domain,” and then each use of the domain is actually a reference to the master definition. If you change the domain, all the uses of the domain automatically change.

    Databases represent Occamal principles in another important respect: statements in the data manipulation language (today, that means statements in SQL, for example SELECT data FROM tables WHERE conditions) are limited to what needs to be done, not how it is to be done. For example, if there is a JOIN between two tables, which should be used first? There is an excellent answer to that question, for example if one table is much smaller than the other, use the smaller table, etc. By abstracting how the join is implemented from the fact that you want a join, you get to define the how of joins in exactly one place, while requesting joins in many places. In earlier data manipulation languages, you could get the job done, but you would explicitly go first to the table you thought best to start from, and then go to the next. The trouble is, this puts the knowledge of how to navigate tables to get information in many places! This is bad because everyone has to learn it and apply it correctly, and if you want to change the method because you’ve figured out a better way to do it, you have to go through all the DML in the program and make individual decisions about how and what to change. Separating what we want from how to get it was definitely an advance, because now SQL could benefit from ever-improving execution routines without having to be changed! The point here is that exactly those benefits are the ones we would expect, because the change also made all programs that use SQL closer to being Occam-optimal!

    It is true that many database implementations are Occam-suboptimal when considered in isolation. Because DBMS schemas are typically completely isolated from the programs that use them, programs that use databases (taking the database schema and stored procedures to be part of the program) are typically far from Occam-optimal. This is recognized in the RAILS framework of the Ruby language, which unifies the data definitions of the database and the program; this is the reason why programming is so much more efficient when using RAILS. Apart from RAILS, it is wonderful to have modern databases as an example of an island of software in which Occamal principles are accepted and valued, and the benefits widely enjoyed. By understanding the examples of good database practice in terms of Occam optimality, we can get an idea of how the principle can be extended to the rest of software.

     

  • Why should you build Occamal Programs?

    There is a good deal of background and analysis to understand just how the concept of Occamality applies to the practical details of building programs. But before we get to that, perhaps it would be good to review the benefits we can expect. The core benefit of paring down a program to its bare minimum information content is pretty simple:

    To the extent that any semantic concept is repeated anywhere, in any form, in the specification of the program, it is a redundancy that, if discarded, would reduce the cost of implementing the concept, the cost of one or more of the downstream components of the program, and the cost of subsequent modifications.

    In other words, an Occamal program is one that is quicker than any other program that does the same thing to build, and is overwhelming the easiest to change, even though you did not think you were building “flexibility” into the program!

    Let’s review briefly the lifecycle of software. At the beginning of the process for a whole new program or a change to an existing one, there is the need to create or change embodied in a set of requirements. From there, with variations depending on the programming shops’ methodology, we have roughly specifications (business, functional, high level, low level, etc.), design (various levels of focus and detail), code (perhaps with prototypes, code walk-throughs, etc.), test (various levels, sometimes performed by different groups of people using different tools), document (internal and external), train (the people who operate, administer, install, support and use), learn and use the software. This sequence may be linear or it may have iterative cycles. Once the program is in operation, there is an extended support cycle, with support, maintenance and bug fixing. There is typically a demand for new or altered features; these go through a version of a similar chain from requirements through building and use. It is generally recognized that (1) most efforts to build new programs crash and burn prior to roll-out, and (2) most of the money that is spent on a program is spend during its extended “tail,” namely the support and modify cycle. The difficulty of building brand-new programs increases the extent to which existing programs are modified, sometimes through multiple technology cycles.

    Today, because occamality is not a familiar concept, it may take longer in practice to build programs that are occamal. Even when it is understood, redundancy frequently does not cost much to build into a program. In fact, it may be quicker to build a program with extensive redundancy (think copy and modify) than with less. But every superficial gain from redundancy is paid for, over and over again. Once we’re past the learning curve, building occamal programs should cost about the same as non-occamal ones (ideally, they would cost less to build), and the majority of the cost of software ownership should experience dramatic benefits. The benefits would mostly be due to the lower cost and lower risk of testing, documenting, learning, using, maintaining, and changing programs.

    What exactly is it that makes programs hard to change? Once you understand basically what you have to do, it comes down to finding all the places in the program that will be affected by your change. The side-effects are always the toughest.

    What if the change you wanted to make could be accomplished by changing exactly one place in the program? What if, to take a trivial example, you wanted to change the classic

    Print (“Hello, world”);

    By printing “bubba” instead of “world?” This would be easy, because you could just go to the single program line and make the change.

    Now let’s take a well-known horrible example – the Y2K problem. This was the problem of modifying programs so they would continue to work when the year changed from 1999 to 2000. This was a problem because many programs did not use 4 digits to represent the year. For various reasons, usually involving an attempt to save space or time, year was represented as a two digit number in many programs, for example 99, with the leading two digits, 19, understood. If those programs had a single place where the number of digits in a year was represented, solving the Y2K problem would have been trivial – you would just go to each program, find the place where year was defined, change it, re-compile, check for problems, and you’re done. A quick change, low risk, no big deal. So Y2K was a problem not because of anything difficult or mysterious about dates – in fact, it could have been about any similar program change. Y2K was a problem simply and solely because the knowledge of the number of digits in the year of dates was expressed in many ways in many places, and it took a long time to find and fix them all with a substantial risk that some places were missed.

    I completely admit, and I remember because I participated in the madness, that there were bizarre variations that made Y2K particularly gruesome. One example is “overloading,” which means that sometimes a programmer would use the value of “99” in the year field to mean “no date was given.” Y2K was a problem before the year 2000 because some programmers used “9999” (which could mean September 9, 1999) to mean “no more records in this sequence.” But all such cases just multiplied the basic fact: the number of digits in a year was expressed in many ways in many places, and in some of those places, other values or indicators were also stored.

    So we want to have exactly one place in which the number of digits in date is defined. Notice that doesn’t mean we are limited to a single date. The key concept here is distinguishing between definition and use. Let’s add another level to make it clear. We want to define date in one place. Then we define, say, a couple of dates: birth date, marriage date, date of loan start, date of loan end. Each of these would be defined as types of dates. “Date” would have how many digits are in a year, and “birth date” would be a kind of date. We would define with “date” those things that are true of all dates, like number of digits in the year. We would define in “birth date” only those things that were true of “birth date” in particular, for example, the label to use when displaying it.

    This is an elementary concept as I have illustrated it so far. What is different is the extent of the application of the concept that I propose. While it is (I hope) common practice for dates to be defined in this way within a program, it is certainly not common practice for all dates used anywhere in a program for any purpose to be defined in this way, as we saw big time in Y2K. For example, we have one way of defining dates in the database, another one for local storage in application programs, and yet another one for display and reports. While it is reasonable for there to be aspects of dates that some parts of programs care about that others don’t, for example the display label, it is not reasonable that all aspects that are common be defined redundantly – they should be defined exactly once.

    More importantly, this concept applies to all aspects of the software lifecycle, not just the building phase. It even applies to documentation, training and using programs, because it means that there is less to document, train and learn, and when changes are made, the user’s common-sense notion that “something changed” actually applies – for example, if zip code is changed from 5 numbers to 5 numbers optionally followed by 4 numbers, that change is universal. The change, made in a single place, ripples though screens, applications, temporary variable definitions and databases.

    Occamality directly addresses a lament frequently heard from programmers, about not being given enough time to do a job “right,” to design it for future flexibility. One of the many reasons good managers refuse to support a “good, flexible design” is that you always pay the price of the additional effort, and you rarely actually experience the benefit. That is simply because the designer tries to anticipate the nature of the potential future change, and make provisions for it. But of course, what usually happens is the anticipated change doesn’t happen and something else does, and the fact that the program is longer than it could have been because of the additional code that provides for un-needed flexibility makes the unanticipated change harder to make than it had to be.

    Now that we understand what makes change hard – the fact that what we want to change is expressed in many ways in many places, all of which have to be found, understood, and correctly changed – we can design programs that are both as quick as possible to build and as quick to change in the future, regardless of the new requirement; we know that if we need to change something, there’s always one place to go to make the change.

    The answer to why you should build Occamal programs is simple:

    Occamal programs cost less to specify, design and build (once you are past the learning and acceptance curves), cost much less in the later stages of the software lifecycle where most of the costs are incurred, and enable changes and other forms of support and maintenance to be made with the greatest speed and the lowest cost and risk. And this is true regardless of language, operating system, application environment, and anything else about your software environment and tools.

     

  • How do you know if a given piece of software is good?

    Software has a real problem. Let me explain.

    While a huge gulf separates the novices from the experts in every field, I like to think that the widespread simple knowledge in most fields is like writing as taught to elementary school students. Fifth graders use the same alphabet that I use; while my vocabulary is more extensive and my use of grammar more elaborate, in both cases what I do extends and builds upon what the kids do. Fifth graders don’t need to unlearn the “bad” letters when they get to high school. Books for children can be well-written, and understood and enjoyed by both children and adults. Books for adults are supersets of children’s books in terms of vocabulary, sentence structure and experience. And while professional writers may not make extensive use of notes written on 3 by 5 cards the way English teachers used to make kids do in high school, the principles of organization are the same.

    In software, however, the doctrines and received methods taught and practiced in the grades and, worse, among mainstream professionals, are simply inadequate to support doing a really good job; the best people don’t extend them, they ignore them and in various ways violate their principles. The typical methods for performing the quality assurance and testing functions, for example, are counter-productive. They don’t need correction – they need complete replacement. They focus on the wrong issues, they have the wrong concepts, and the most widely used methods and tools simply don’t get the job done!! The relationship between programs and data. Same. By reference and by value, implicit and explicit. Other books in this series go into detail for a couple of these subjects.

    Things are so bad in software that the most experienced and accomplished people don’t even agree on what makes a program “good.” Given a set of programs that don’t crash and meet a set of requirements, how do you rank them in order of goodness? Is goodness proportional to how deep the inheritance trees are? How well documented they are? To what extent the evil “go to” mechanism is used? What is the test coverage, or the number of unit tests? How few machine resources they consume? Whether they’ve been written in this language or that?

    I propose that there is, with a few common-sense qualifications, a measure of software goodness we can all agree to. I suggest this isn’t a new idea, but one that many people have sensed and acted on. The principle even makes common sense! The only thing it lacks is articulation and discussion. Here is a non-technical explanation of it. Here is one of my attempts to state the principle in a historic and more technical context. Here is a deeper explanation of the context and background.

    This is not an abstract, nice-to-have concern. Unless you know what “goodness” is in a program, how can you measure whether you’re going in the right direction? Think about target shooting: without a target, how can you decide how close you are, and therefore how accurate a shooter you are? How can you compare two different shots?

    Having an explicit agreement of what makes a program “good” is indispensable to making good software, and making it effectively and efficiently.

  • Occam’s Razor: the key to optimal software development

    William of Occam (ca. 1285 to 1349) was an English logician and Franciscan friar. He is credited with formulating a principle that has been applied to various aspects of computer systems. In those areas of computing to which it has been applied, it reigns supreme – it supplies optimal solutions to the relevant problems.

    There are large areas of computing to which Occam’s razor has not been applied. Worse, it is not even one of the candidates under consideration. As a result, those aspects of computing are fractured, inefficient, unpredictable, and driven by fashion and politics.

    Everyone involved knows that the whole process of specifying, designing, building, testing and supporting software is hopelessly inefficient, unpredictable and error-prone. The leading methodology that concentrates on the process of building software, “project management,” is theoretically bankrupt and in any case has an empirical track record of failure. In terms of the content of good software, there are fierce battles among competing approaches, none of which is anything but a collection of unsupported and unfounded assertions, and which in practice don’t contribute to building good software.

    Occam’s razor leads to the principles on which good software may be built, and supplies a single simple, widely applicable theme that, when applied, cuts away (as a razor should) all the inefficiency and generally what we don’t like about software. Once the principle is understood and widely applied, It should be the undisputed standard for how software is built, just as it has in the other areas of computing to which it has been applied.

    Here is a shorter attempt to explain the Razor and its application to software. Here is an approach to the same problem from a common-sense layman's point of view.

    The razor itself

    “Occam’s razor” is a famous principle of thinking from the European Middle Ages. Occam’s razor is applied in situations where there is more than one reasonable explanation for a phenomenon, and basically says that you should pick the simplest explanation consistent with the phenomena you observe. From Wikipedia:

    Leonardo da Vinci (1452–1519) lived after Occam's time and has a variant of Occam's razor. His variant short-circuits the need for sophistication by equating it to simplicity.

    Simplicity is the ultimate sophistication.

    Occam's Razor is now usually stated as follows:

    Of two equivalent theories or explanations, all other things being equal, the simpler one is to be preferred.

    As this is ambiguous, Isaac Newton's version may be better:

    We are to admit no more causes of natural things than such as are both true and sufficient to explain their appearances.

    In the spirit of Occam's Razor itself, the rule is sometimes stated as:

    The simplest explanation is usually the best.

    Other applications of Occam’s razor

    While it plays little overt role in intellectual debates, in fact Occam’s razor and concepts derived from it are central to scientific thinking. So while you may not have ever heard of it, or may only vaguely remember having heard it in the past, you shouldn’t think that it’s an obscure little Medieval tidbit that has no relevance to the present that this guy is just pulling out for some weird reason. If you go through the Wikipedia reference, you find that:

    Occam's Razor has become a basic perspective for those who follow the scientific method. … without the principle of Occam's Razor science does not exist. The primary activity of science, formulating theories and selecting the most promising theory based on analysis of collected evidence, is not possible without some method of selecting between theories which do fit the evidence. This is because, for every set of data, there are an infinite number of theories which are consistent with those data (this is known as the Underdetermination Problem).

    You can find Occam’s razor in detail in astronomy, physics, biology, and medicine. It even appears explicitly in statistics.

    There are various papers in scholarly journals deriving versions of Occam's Razor from probability theory and applying it in statistical inference, and also of various criteria for penalizing complexity in statistical inference. Recent papers have suggested a connection between Occam's Razor and Kolmogorov complexity.

    It should be evident that Occam’s razor is an important underpinning of the whole scientific enterprise.

    Applications of Occam’s razor in computing

    We already understand Occam’s razor clearly in information theory, in which we measure the information content of a transmission. Information theory has provided the theoretical foundation of all communications and data transmission since its invention by Claude Shannon in 1948.

    Occam’s razor is particularly applied in minimum message length (MML) theory, which focuses on the least number of bits required to encode a given amount of information. 

    MML has been in use since 1968. MML coding schemes have been developed for several distributions, and many kinds of machine learners including: unsupervised classification, decision trees and graphs, DNA sequences, Bayesian networks, Neural networks (one-layer only so far), image compression, image and function segmentation, etc.

    While the terminology is not normally used, and I am not aware that Occam’s razor was explicitly used to formulate it, it is clear that the principles are clearly expressed in modern relational database theory, and in the practice of schema design. I suggest that is one of the reasons for the success of the DBMS approach to data storage and access.

    Shannon’s information theory

    Shannon’s application of the concept to information theory provides a good springboard to seeing how it applies to software design. So let’s understand information theory a little better. I don’t think I can do better than Wikipedia. Here is a snapshot of the article on the history of information theory:

    Claude E. Shannon (19162001) founded information theory with his classic paper "A Mathematical Theory of Communication," published in the Bell System Technical Journal in July and October of 1948. At the beginning of his paper, Shannon asserted that "The fundamental problem of communication is that of reproducing at one point, either exactly or approximately, a message selected at another point." His theory for the first time considered communication as a rigorously stated mathematical problem in statistics and gave communications engineers a way to determine the capacity of a communication channel in terms of the common currency of bits. This problem is called the channel coding problem. The transmission part of the theory is not concerned with the meaning (semantics) of the message conveyed.

    A second set of ideas in information theory relates to data compression. Using a statistical description for data, information theory quantifies the number of bits needed to describe the data. There are two formulations for the compression problem — in lossless data compression the data must be reconstructed exactly, whereas lossy data compression examines how many bits are needed to reconstruct the data to within a specified fidelity level. This fidelity level is measured by a function called a distortion function. In information theory this is called rate distortion theory. Both lossless and lossy source codes produce bits at the output which can be used as the inputs to the channel codes mentioned above.

    This division of information theory into compression and transmission is justified by the information transmission theorems, or source-channel separation theorems that justify the use of bits as the universal currency for information in many contexts. …

    Communications channels have a fixed capacity for sending information per unit of time. To use that capacity as efficiently as possible, you distinguish between the message that is presented for sending and the actual information content of that message. What this amounts to is saying that the “information content” of a message is the smallest number of bits required to exactly reproduce the message after transmission. In plain language, the “information content” of a message is the message compressed as much as possible, with all repeats and redundancy removed, except for redundancy purposely introduced for error identification and correction.

    Like any application of Occam’s razor, the focus on information content comes out of knowing what you care about; you include everything required to get what you care about and throw out everything else. What I care about in communications is accuracy and efficiency. Efficiency means that I should transmit the most information through a communications channel of given capacity as possible. This can be achieved by using the smallest possible number of bits to encode the message. 

    The application of Information theory to software

    How is all this relevant to building software? Aren’t we supposed to use structured design, use cases, components, or whatever to design software? Most of those techniques focus on the process of a good design, or a supposed ideal structure for a program. If we apply the same thinking that we see in information theory to software design, we will focus instead on the results of the process, and once we are satisfied we know how to judge whether a computer program is optimal or not, we will be able to find ways to build it.

    Software specification and design has clearly been an island of technical art, separated from science and technology as a whole, except for those portions that have already come under the sway of “Occamal” thinking such as information and MML theory. Like any relatively isolated island of theory and practice, a wide variety of techniques and practices arise to fill the gap left by a completely baseless, ad-hoc approach. There are innumerable approaches to software design and building and no clear way to decide among them.

    When designing software, we care most about things that are a very close analogy to what we care about in communications. In communications, we have a channel of given capacity, and want to squeeze the most information through it we can; therefore, we eliminate all redundancy from the original message, and transform it to contain only its pure information content. Anything extra would take transmission capacity and add nothing. In software design, we normally have capacity to build a representation of the program (source code) that is as long as we would like in terms of the capacity of the computer to execute the code. However, every line of code adds a burden to one or more stages of the whole chain of specify, design, code, test, document, train, learn, use, maintain, modify, and repeat. This chain of effort, the entire lifecycle of the program and everyone who touches it, is like the communications channel in information theory. The idea is that most program specifications are highly redundant, like messages in their original form. We want to define the “information content” of programs just like we define the information content of messages, so that every redundant or repeating group is eliminated, and what is left is everything required to make the program operate and absolutely nothing else. We focus on information content in communications because we want to make the best use of fixed communications capacity; we focus on information content in software because we want to make the best use of all the resources that are involved with the software in any way.

    We don't just want to make programs short for general reasons. We also want to make them easy to change, with as little effort and error as possible. By eliminating all redundancy from a program, we make it so that there's exactly one place to go to make a change.

    Getting back to Occam (though I admit Shannon and fancy formulas are more impressive and intimidating), if Occam’s razor is:

    Entia non sunt multiplicanda praeter necessitatem.

    No more things should be presumed to exist than are absolutely necessary.

    Occam’s razor applied to software would be:

    No more software entities should be created than are absolutely necessary.

    Why? Just as sending bits beyond the information content of the message has a cost but doesn’t improve the message that is received, so do additional entities in the specification or expression of the program add to the cost to build and the cost to change without increasing the value of the program.

    This may not sound dramatic or exciting. But as someone who has lived with the process of building software for a long time, and has struggled extensively with the question of what makes software “good,” it’s very satisfying to have an objective criterion that enables you to judge the “goodness” of a program, and to say when a program is “optimally” good. It gets exciting when you realize that this abstract notion of optimality has consequences that are extremely practical and down-to-earth. In particular, it shows you a path to building programs more quickly than using any other method; doing less to build the programs than you thought you had to do; and having the resulting programs be as easy and safe to change as it is possible for programs to be.

Links

Recent Posts

Categories