Author: David B. Black

  • The giant advances in software programming languages

    There have been two gigantic advances in programming languages, each contributing huge advances in programmer productivity. Since then, thousands of times more attention has been given to essentially trivial changes than has been given to the two giant advances. I described these 50 years of non-advances here. In this post I’ll go back in history to describe the two giant advances that were made in the early days of computing, back in the 50’s, and I’ll tack on the one important corrective that’s been made since then.

    First, the pre-history of computer languages

    The famous early computer was the ENIAC.

    https://en.wikipedia.org/wiki/ENIAC

    It cost the equivalent about of $7 million to build and took about 3 years. It was big, occupying about 300 sq ft. It was roughly 1,000 times faster than electro-mechanical machines, so you can see why people were excited about it. Its purpose was to perform complex calculations on scientific/engineering data.

    Glen_Beck_and_Betty_Snyder_program_the_ENIAC_in_building_328_at_the_Ballistic_Research_Laboratory

    While the excitement was justified, the method of programming was gruesome.

    “ENIAC was just a large collection of arithmetic machines, which originally had programs set up into the machine[33] by a combination of plugboard wiring and three portable function tables (containing 1,200 ten-way switches each).[34] The task of taking a problem and mapping it onto the machine was complex, and usually took weeks. Due to the complexity of mapping programs onto the machine, programs were only changed after huge numbers of tests of the current program.[35] After the program was figured out on paper, the process of getting the program into ENIAC by manipulating its switches and cables could take days. This was followed by a period of verification and debugging, aided by the ability to execute the program step by step”

    Engineers (all men) would figure out what they needed the machine to calculate. It then fell to the “programmers,” all women, to perform the excruciatingly detailed work with the knobs and switches.

    375px-Two_women_operating_ENIAC_(full_resolution)

    From this it is extremely clear that while the machine was an astounding achievement in speed, the speed of programming the calculation steps was the huge bottleneck. How can we make this faster?

    Answer: instead of physical plugs and switches, let's invent a language for the machine — a "machine language!" That's what happened with the invention of the stored program computer, which took place in 1948. Instead of moving plugs and flipping switches, programming was done by writing it out in machine language on paper, loading it into the computer via punched paper cards, and then having the computer execute it. Figuring out the detailed steps was still hugely difficult, but at least getting it into the computer was faster.

    From machine language to assembler

    Every machine has one and only one “machine language.” This is a stream of binary data that the machine’s processor “understands” as instructions. Each instruction causes the machine to perform a single action on a single piece of data.

    I learned to read and write machine language for a couple different machines. It’s not easy. From early on, machine language was usually shown as hexadecimal instead of raw binary, so that instead of looking at “0100101000101111” you see the hexadecimal equivalent: 4C2F.  A big plus but you’re looking at a hexadecimal pile of data. A nice editor will at least break it up into lines of code, but you still have to read the hex for the instruction, registers and storage locations

    Moving from machine language to assembler language was HUGE. Night and day in terms of readability and programmer productivity. Assembler language is a body of text that closely corresponds to the machine language. Each line of text typically corresponds to exactly one machine language instruction. Assembler language transformed programming. If you understand any machine language, you can easily write and read the corresponding assembly language. For example, here's the binary of a simple instruction:

    1

    Here's the equivalent in hexadecimal:

    2

    And here it is in assembler language, including a comment:

    3

    Just as important as making instructions readable was using text labels for locations of data and addresses of other instructions. In machine language, an address is expressed as a “real” address, for example as a hexadecimal number.  If you inserted a command after a jump command and before its destination, you would have to change the address in the jump. You can see that with lots of  jumps this would quickly become a nightmare. By labeling program lines and letting the assembler generate the “real” addresses, the problem disappears.

    From assembler to high-level languages

    Assembler made writing code in the language of the machine incredibly easier. It was a huge advance. But people quickly noticed two big problems. The solution to both problems was the second giant advance in software programming, high-level languages.

    The first problem was that writing in assembler language, while worlds easier than machine language, still required lots of busy-work. For example, adding B and C together, dividing by 2 and storing the result in A should be pretty easy, right? In nearly any high-level language it looks something like this:

                    A = (B+C)/2

    Putting aside messy details like data type, this would be the following in pseudo-assembler language:

                    Load B into Register 1

                    Load C into Register 2

                    Add Register 2 to Register 1

                    Load 2 into Register 2

                    Divide Register 1 by Register 2

                    Store Register 1 into A

    Yes, you can quickly become proficient in reading and writing assembler, but wouldn’t the 1 line version be easier to write and understand than the 6 line version?

    Expressions were the core advance of high level languages. Expressions turned multi-line statement blocks that were tedious and error-prone into simple, common-sense things. Even better, the use of expressions didn’t just help calculations – it helped many things. While assembler language has the equivalent of conditional branches, many such conditionals also involve expressions, for example, the following easy-to-read IF statement with an expression

                    If ((B+C)/2 > D) THEN … ELSE …

    Would turn into many lines of assembler – tedious to write, taking effort to read.

    The second problem emerged as more kinds of computers were produced, each with its own machine and assembler language. A guy might spend months writing something in assembler and then want to share with a friend at another place using a different type of computer. But the friend’s computer was different – it had a different assembler/machine language! The whole program would have to be re-written. Total bummer!

    Wouldn’t it be nice to write a program in some language that was like the 1 line version above, and that could be translated to run on any machine??

    Easier to write by a good 5X, easy to read and can run on any machine, present or future. Hmmmm… There must be something wrong, this sounds too good to be true.

    The concept of high level languages was good and wasn’t too good to be true. Everyone agreed, and it wasn’t long before FORTRAN and similar compute-oriented languages arose. Even performance-obsessed data nerds wrote programs in FORTRAN rather than assembler because FORTRAN compiled into machine language was just as fast, and sometimes even faster because of optimizations those clever compiler guys started inventing! And the programs could run anywhere that had a FORTRAN compiler!

    The accounting and business people looked at what was happening over in heavy-compute land and grew more and more jealous. They tried FORTRAN but it just wasn’t suitable for handling records and transactions, not to mention having nice support for financial data. So business processing languages got invented, and COBOL emerged as the best of the bunch.

    If you look at a compute statement in FORTRAN and COBOL, they’re nearly identical. But in the early days, FORTRAN had no support for the money data type and no good way to representing blocks of financial data that are core to anything involving accounting.

    Once they got going, people just kept on inventing new languages for all sorts of reasons. The obvious deficiencies of FORTRAN and COBOL were fixed. Languages could handle intense calculations and business data processing about as well. But back around 1970, 50 years ago, there remained a gap. That gap was that an important category of programs could not be written in any of the high-level languages. Essential programs like operating systems, device drivers, compilers and other “systems” software continued to be written in the assembler language of the machine for which it was intended. There were attempts to fill this gap, but they failed. Then a couple super-nerds at Bell Labs, building on an earlier good shot at solving the problem, invented the language C.

    Lang 2
    They rewrote the UNIX kernel in C, and the rest is history – C became the high-level language of choice for writing systems software and still holds that place.

    Conclusion

    Two giant advances were made in programming languages. Each of these happened early in computing history, in the 1950’s. The first giant advance was the biggest: with assembler language, machine language was reasonable to write, read and change. The second giant advance was the category of high level languages. Two minor variants on the concept, COBOL and FORTRAN, established the value of having a language that enabled expressions and could be compiled to run efficiently on any machine. In spite of the on-going tumult of language invention that has taken place since, the fact that huge bodies of working code written in those two languages continue to perform important jobs makes it clear that they embodied the giant advance that was high level languages. The only substantial omission in those languages – the ability to directly reference computer memory – was filled by the invention of the language C.

    Most of what’s happened since in programming languages is little but sound and fury. For a review of those non-advances see this.

    I do appreciate some of the subtle changes that have been made in language design. Some modern languages really are better – but mostly not because of the details of the language! I’ll treat this issue in a future post. Meanwhile, it’s important to understand history and appreciate the giant steps forward that high level languages as a category represent.

  • Software Programming Languages: 50 years of Progress

    I was inspired to examine 50 years of progress in computer languages by an article in the Harvard alumni magazine written by one of the leading figures in Harvard computer activity, Harry Lewis. Lewis graduated from Harvard College the year I entered, and he stayed on for a graduate degree while I was a student there. He says:

    Thirty veterans of Harvard’s Aiken Computation Lab reunited on January 19, 2020, some 50 years after each of us had a role in creating today’s networked, information-rich, artificially intelligent world. Rip van Winkles who had never fallen asleep, we gathered to make sense of what had evolved from our experience as undergraduates and Ph.D. candidates during the decade 1966-1975. One thing was clear: we hadn’t understood how the work we were doing would change the world.

    I interacted with many of the people and projects he describes in the period he focuses on. For this post I decided to focus just on one of his major topics, programming languages.

    50 years of progress

    You might think a book would be required to adequately describe the advances that have been made in programming languages in the last 50 years. In fact, many experts seem to think so. Programming languages continue to advance and improve, even with everything that’s been achieved in the last 50 years – and more!

    There is no doubt that many programming languages have been introduced in decades past. The pace of new language introduction does not seem to have slowed. But has progress been made? Yes – if you count dead-ends, bad ideas, going in circles and trivial variations as progress.

    While describing the true progress in programming languages is easy, explaining why all the widely-touted “advances” aren’t in fact progress would indeed take a book. Which someone other than me is welcome to write. It would be boring! What could you expect from a gruesomely detailed exposition that amounts to Idea 1 is stupid because …; Idea 2 isn’t any better because …; idea 3 just another attempt with slightly varied syntax to go after the same fruitless goal as Idea 4, decades before …

    I gave a talk that included this subject to a large group of programmers in India 25 years ago. Here is the slide illustrating the mighty progress of languages as illustrated by what COBOL calls a Compute statement:

    Lang 1

    I hope that gives you a basic idea of the massive advances that had been achieved by the mid 1990’s.

    The same progress has continued unabated until the present. Google is promoting the language Go, often called Golang. Go must be one terrific language if the geniuses at Google are behind it, right? Here’s that same simple assignment statement I illustrated decades ago, updated to show how Google has made it even better:

    A:=B*C+D

    This illustrates the exquisite judgment expressed in new language design: The assignment statement has the colon before the equals sign, like PL/1, but leaves off the ending semicolon. Genius!

    Uncommon common sense about programming languages

    The inventors and promoters of new programming languages nearly always talk about how the wonderful new language is "better" than all other languages. Frequently mentioned are that the new language helps programmers be more productive and commit fewer errors.

    In my experience and subjective judgment, all such claims are false and simply not proven out in practice. More important is the fact that the inventors/promoters of new language have no real arguments beyond their own enthusiasm to back their claims: there is NO evidence-backed science to support ANY of the claims that a given language is superior on some measure than others. There isn't even any substantial agreement on the appropriate measure of goodness, much less an evidence-based hierarchy of languages against the measure of goodness!

    That should be the end of it. Once you realize how devoid of evidence, experimentation and science the whole endeavor is, it becomes clear that anyone promoting the virtues of a new language is either an ignorant buffoon or self-promoting cult leader. Or some of each.

    Following are some observations to help put this into context.

    I do understand how the enthusiasm for a new language can catch hold. Being a programmer requires a powerful set of blinders and the ability to focus on an incredibly narrow field for long periods of time. It's essential to being a good programmer! But you have to step back and look at your enthusiasm objectively. Above all you have to have objective measures to compare your wonderful new language to the bad old ones. This is almost never done in software, though it's commonplace in other fields. Would Marie Curie have been a better scientist had she used German instead of French as her primary language at work? See this for more.

    There is a hierarchy of skills in software. Knowing a programming language is an important part of the hierarchy but it's near the bottom of the stack! Think about learning a new human language as an adult, ignoring for the moment the huge advantage you have being proficient in a language. You start with basic vocabulary and grammar. How long and hard is it to get the accent a native speaker has? Now think about vocabulary, the basic subset you've learned vs. the huge set of the native speaker. Think about using the basics of the language to get things done compared to using the language as an excellent writer or speaker. Now think about idiomatic expressions, of which any native speaker has a huge set — without them, you're not fluent. Finally, think about a profession like law or medicine. Those proficient are using the base language, but with a vocabulary,, knowledge and sophistication that take years to learn. These things are like the subroutine library that is a key part of any language though not strictly speaking part of the language itself, and the professional specialty is like networking or database. Yes, the core language is a necessary foundation, but most of the real skill is in the rest. See this for more depth on this important subject.

    It turns out that the "goodness" of a software effort isn't really dependent on the language used! When you dig into what really matters, it turns out that factors outside the strict confines of language design are overwhelming important, though details that new-language enthusiasts tend to ignore can play a role. See this for details.

    One more key factor in the explosion of languages that are touted as advances but are really just a variation on the same old thing is the core human behavior of creating a language among people who work together on the same things for long periods of time. But no one has found that any of these languages are superior in some real way than others — they're just the languages that happen to have evolved, each with some unique vocabulary reflecting unique concerns, like the words that people who live in the arctic have for different kinds of snow and ice. This is a well-known behavior, and why shouldn't it also be seen when people "speak" computer languages together? See this for examples and details.

    When you lay out the spectrum of languages, you can see some patterns. The most obvious of the patterns I've observed is the extent to which data is defined as part of the language itself or outside the language proper. Data can be fully accessed and manipulated in all cases — the difference is the extent to which the data definitions are made part of the language itself, or as part of a core library attached to the language. Language mavens are passionate about each of the variations, and convinced that theirs is best! See this for details.

    What among other things enables large groups of people to hail the latest "advance" in computer languages without being laughed out of town is the shocking ignorance and lack of interest in computer and software history everyone involves exhibits. With the least bit of software history knowledge, no one would have the nerve to invent a new language, much less brag about it. See this for more.

    What does this mean?

    If you're a techie, you should get a grip, some perspective and knowledge of history and science. It will help you see, for example, that the fact that Marie Curie's native language was Polish and that she worked largely among French speakers was incidental to her great mind and achievements. It will help you see that Shakespeare wouldn't have been a much better playwright if only he had written in Latin (or whatever), or would have been much worse had he written in Norse (or whatever).

    If you're a manager, you should respect the enthusiasm of your employees but understand the fact that their enthusiasm is baseless. I saw a software re-write into a new language using the Neo4j database. Everyone was pumped. Disaster. I have seen a couple cases in which huge enthusiasm was behind a less radical choice. The results were no better in any way than using a more standard language — the engineers worked harder than they would have because of their enthusiasm, but were less productive because they were less skilled in the new environment. And of course, new hires were hampered with the same problem.

    Conclusion

    Computer Science is a profoundly unscientific field. The fashion-driven nature of it is exhibited starkly in the decades-long march of revolutionary new languages that keep getting invented — and having no impact on anything that matters.

    If you want to be the best possible programmer, it's incumbent on you to use a sensible, mainstream language and spend your effort producing excellent results — including bringing the whole notion of excellence to new levels. The language you use will not be the limiting factor — what's important is the way you use the language, just as it was for Marie Curie.

  • Computing in 1968: Gender, Cards, etc.

    I grew up in Denville, a little town in northern New Jersey. I had a friend whose father knew someone who worked at what was then called EMSI, Esso Mathematics and Systems Inc., housed in a big complex on Park Ave. in Florham Park, NJ. I don’t think I even was interviewed, but I ended up with a job there the summer after graduating from the local public high school in 1968!

    EMSI was a service company, one of over 100 companies in the Standard Oil of NJ group of companies. The purpose of the company was to apply advanced math and computer techniques to make the various Esso companies work better. The company had a large computer center on-site, a large room full of card keypunch machines, and extensive offices.

    There was a strict division of work by sex. There were secretaries, all women. The men, all dressed in white shirts and ties, were the math and software design people. Software design was done using graph paper and plastic sheets that had flowchart cut-outs in it, so you could make uniform branch triangles, etc.  Here’s a picture of what it looked like (not mine, I never had or used one): 111

    The programming was all done by women, who wrote lines of code onto coding paper, with lines and columns that matched up with Hollerith cards. This was supposed to be a mechanical affair, driven by the graphical designs. Of course it was more than that. When a sheet was ready, it would be sent for keypunching, all done by women using keypunch machines. I think we used the newer IBM 026 machines. The programmers, all women, would get the cards and sort them in a rigid box for storing and transporting to the machine room, where male machine operators would stack them into card readers for loading into the computer. Often there were errors, of course, so the machine would print the error listing on wide, 132 column paper using a mechanical printer. The paper had a string of square holes along each side that fit into gears in the printer. The printers were “line printers,” printing a single line of characters and numbers on the paper. Once the line was printed, the gears would advance the paper one line, and the next one would be printed. The pages were all joined end-to-end, fed to the printer from a big box sitting beneath it. When a print job was complete, the last page would be advanced out. An operator would tear the print jobs apart from each other and put them on a table for people to pick up, along with any related cards to the programmer. The printout could be a list of error messages from the compiler, maybe along with a printout of the program itself. You could ask for the assembler language version of the program to be printed along with the original source code in FORTRAN, which was important when debugging. If the program compiled properly, i.e., had no syntax errors, it would be run. It would either run to completion and print out the desired results, or it would crash, in which case a listing would be printed including a memory dump, which was a hexadecimal listing of the contents of the memory at and around the cause of the crash. I spent many totally absorbed hours poring over and deciphering memory dumps.

    The physical embodiment of a program was an ordered set of cards. You would carry the cards for a program around in a cardboard box, all lined up in a neat stack. The box was as wide and high as a card, and at least a foot long, long enough to carry 2,000 cards.  Every once in a while someone carrying a box of cards would stumble and drop the box, scattering the cards on the floor. A fun time would then ensue, figuring out the right order of the cards and putting them back. This is one of the reasons that the last handful of columns in many card decks contained the sequential number of the card in the program, or set of data, or whatever; without such numbers, putting the deck back together would take even longer. I dropped a deck once. It’s the kind of thing that, once you did it, you took great care never to do again, quite apart from the people around you in the hallway laughing at you.

    I don’t know how it happened, but I was the exception – a tall, skinny, male high school grad who was bright but entirely without qualifications. Everyone seemed amused by my existence. Perhaps that’s why I got away with things. It’s probably also why I kept getting asked to do things that cut through the otherwise strict divisions of labor. For example, I skipped the usual two-step of getting programs written, the design part by tie-wearing men using plastic guides to make neat-looking diagrams of program operation and flow, followed by women “translating” the design into actual lines of code. What a waste of time, I thought. Just work out what you wanted to do in your head, and then write the code. Before long I skipped the write-the-code-on-paper part, and just typed it into a vacant keypunch machine in the sea of lady keypunchers.

    Looking back on the experience, I realize how lucky I was, and how unusual the experience I had working for a large division of a giant company. I now know that there must have been projects with goals and timelines that had to be met. People were judged based on whether they hit the pre-determined goals. While I was stuck into that environment, I was there as an un-planned-for extra resource who fit into none of the pre-defined categories. People threw me bits of work to keep me busy, without ever telling me how and when it had to be done. Each task involved something I had to learn, often a lot I had to learn, so I just tore into it. When I was done, I presented it to the person who gave me the work, much like a dog who dashed off to fetch a ball someone had thrown, perhaps into a lake. I imagine I looked as eager and pleased with myself as a dog, ready to dash after another ball. I never focused on the learning; I just drove towards the ball, overcoming obstacles (mostly things I didn’t know, sometimes the strict hierarchies and divisions of labor) as quickly as I could along the way. It was a formative experience, and one that was at odds with the normal group working experience. I knew I was lucky to have the job, and my appreciation for how lucky I was has grown over the years.

    This is an edited excerpt from the draft of my Computer-related Memoir.

  • Job requirements for software engineers should stop requiring CS

    I've read thousands of job requirements for computer programmers over the years, and written or edited quite a number. I’ve interacted with hundreds of software groups and seen the results of their work. I’ve spent a couple decades cranking out code myself in multiple domains. There are a couple near-universal problems with job requirements that, if changed, would improve the quality of software groups and their productivity.

    Of course, it’s not just the job requirements and what the hiring people do – it’s also the managers, from the CEO down. They also have to not just support but champion the changes I describe. If they do, everyone will enjoy better results from the software team.

    In this post, I'm going to concentrate on just one of the issues: academic degrees

    A near-universal job requirement is an academic CS degree. When analytics, ML or AI is involved, the requirement is often “upgraded” to a Master’s or PhD.

    There are many capable programmers who have degrees of this kind. Often it doesn’t seem to hurt or hold them back much. But all too often it does! The more specialized the training, for example in project management or quality, the more likely the “education” the person has received is an active impediment to getting good work done.

    Here’s the simple, raw, brutal fact: Getting a degree in Computer Science does NOT train you to become an effective programmer in the real world. All too often, the degree results in the person performing worse than someone with self-training and apprentice experience.

    That is the fact. Surprised?

    Let’s do a little compare and contrast with medicine. Yes, I know that an MD is a graduate degree, while CS is often undergrad. Medical training has evolved to what it is now after decades and centuries of finding out what it really takes to help make people healthy. By contrast, CS degrees just started being granted 50 years or so ago, and are far from even trying to figure out what kind of training helps create good programmers.

    First let’s look at the training and testing:

    • You don’t even get into med school without taking the MCAT, a challenging test that takes over 7 hours that few do well on.
    • Once you’re in med school you take a four year course to get your MD.
      • The first two years are academic, including hands-on labs. Then you take the USMLE-1. If you don’t pass this challenging test you’re out. End of med school.
      • The second two years are clinical! You’re in hospitals, clinics and offices seeing patients under supervision. And you’re graded. And then you take the USMLE-2, which is harder than part 1 and has lots of clinical stuff. If you fail, you’re not an MD.
    • To practice, even as a general practitioner, you have to apply and be accepted into a Residency. Depending on specialty, this can be 3-7 years of mostly hands-on practice, under close supervision.
      • During your first year, you have to take and pass the USMLE-3. Fail and you’re out.
      • During your last year you have to take and pass the test specific to your specialty. Fail and you’re out.

    Here’s the equivalent of the training and testing in CS:

    • There is NO equivalent in CS. No entry testing. No exit testing. Just grades on courses determined by professors who usually pass everyone.

    A little compare and contrast between medicine and CS:

    • Medicine is taught by doctors who practice medicine
      • CS is taught by professors, most of whom have never practiced programming in the real world.
    • A large part of medical training is working with real patients with real problems, under the supervision of practicing doctors.
      • CS is primarily classroom teaching with textbooks and homework exercises. You have to write programs as exercises, but it’s completely artificial. There is nothing apprentice-like or truly clinical about it.
    • Medical training is led by doctors who are incented to produce great doctors.
      • CS training is led by academic PhD’s with no real-world experience who are incented to publish papers read by people like them.
    • Medical journals publish essential information for practicing doctors, giving advances and new discoveries.
      • CS journals are read by the tiny group of academics who publish in them. Practicing programmers pay no attention for good reason.
    • Bad doctors are fired for incompetence and barred from practicing.
      • CS graduates are rarely fired for incompetence. If CS graduates can’t program well, they usually shift into using their non-skills in “management.”
    • In medicine, best practices are increasingly codified. You rapidly fall under scrutiny for deviating.
      • CS grads seek out and follow fashions that are the software equivalent of blood-letting, enthusiastically promoting them and getting them adopted with disastrous results.
    • Hospitals are compared with each other in terms of results. It’s not hard to find which are the best hospitals.
      • Groups of CS grads make it impossible to make comparisons between groups, with the result that huge groups produce major disasters at great expense, while tiny groups of effective programmers perform 10X or more better.

    All this doesn’t make things uniformly wonderful in medicine. But it goes a long way towards explaining why software is so bad. It’s awful. The awfulness is so widespread that it’s rarely talked about!. If bridges fell down at 1/100 the rate that software projects fail, there would be a revolt! Instead, everyone in the industry just sighs and says that’s the way things are.

    You think things are great in software? Check out a couple of these:

    https://blackliszt.com/2015/09/software-quality-at-big-companies-united-hp-and-google.html

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

    https://blackliszt.com/2014/02/lessons-for-software-from-the-history-of-scurvy.html

    The fact is, CS training leads to horrible results because Computer “Science” is roughly at the same level as medicine was when bleeding patients was the rule. See this:

    https://blackliszt.com/2019/11/computer-science-is-propaganda-and-computer-engineering-is-a-distant-goal.html

    Conclusion

    There are lots of things you can do to improve the results of hiring software programmers and managers. Here's how the usual interview process goes; here is specific advice about interviewing. There is a whole pile of advice in my book on software people. If all you did was drop the CS degree requirement, you would have taken a big step forward in quality improvement.

  • Why is a Monolithic Software Architecture Evil?

    Why is a monolithic software architecture evil? Simple. There is no need to explain “why,” because monolithic is not evil. Or even plain old bad. In fact it’s probably better than all the alternatives in most cases. Here’s the story.

    The Cool, Modern Programmers Explain

    The new, modern, with-it software people come in and look at your existing code base. While admitting that it works, they declare it DOA. They say DOA, implying “dead on arrival.” But since the software apparently works, it can’t be “dead,” except in the eyes of the cool kids, as in “you’re dead to me.” So it must be “disgusting,” “decrepit,” “disreputable,” or something even worse.

    Why is it DOA (whatever that means)? Simple: … get ready … it’s monolithic!! Horrors! Or even better: quelle horreur!!

    Suppose you don’t immediately grimace, say the equivalent of OMG, and otherwise express horror at the thought of a code base that’s … monolithic!! … running your business. Suppose instead you maintain your composure and ask in even, measured tones: “Why is that bad?” Depending on the maturity level of the tech team involved, the response could range from “OK, boomer,” to a moderate “are you serious, haven’t you been reading,” all the way up to a big sigh, followed by “OK, let me explain. First of all, if an application is monolithic, it’s so ancient it might as well be written in COBOL or something people who are mostly dead now wrote while they were sort of alive. But whatever the language, monolithic applications don’t scale! You want your business to be able to grow, right? Well that means the application has to be able to scale, and monolithic applications can’t scale. What you need instead is a micro-services architecture, which is the proven model for scalability. With micro-services, you can run as many copies of each service on as many servers as you need, supporting endless scaling. Even better, each micro-service is its own set of code. That means you can have separate teams work on each micro-service. That means each team feels like they own the code, which makes them more productive. They’re not constantly stepping on the other teams’ toes, running into them, making changes that break other teams’ work and having their own code broken by who-knows-who else? With monolithic, nobody owns anything and it’s a big free-for-all, which just gets worse as you add teams. So you see, not only can’t the software scale when it’s a monolith, the team can’t scale either! The more people you add, the worse it gets! That’s why everything has to stop and we have to implement a micro-service architecture. There’s not a moment to lose!”

    After that, what can a self-respecting manager do except bow to the wisdom and energy of the new generation of tech experts, and let them have at it? All it means is re-writing all the code, so how bad can it be?

    One of the many signs that “computer science” does little to even pretend to be a science is the fact that this kind of twaddle is allowed to continue polluting the software ecosphere. You would think that some exalted professor somewhere would dissect this and reveal it for the errant nonsense it is. But no.

    Some Common Sense

    In the absence of a complete take-down, here are a few thoughts to help people with common sense resist the crowd of lemmings rushing towards the cliff of micro-services.

    Here's a post from the Amazon Prime Video tech team of a quality checking service they had written using classic microservices architecture that … couldn't scale!! The architecture that solves scaling can't scale? How is that possible? Even worse is how they solved the problem. They converted the code, re-using most of it, from microservices to … wait, try to guess … yes, it's your worst nightmare, they converted it to a monolith. The result? "Moving our service to a monolith reduced our infrastructure cost by over 90%. It also increased our scaling capabilities."

    Here's the logic of it. Let’s acknowledge that modern processor technology has simply unbelievable power and throughput. Handling millions of events per second is the norm. The only barrier to extreme throughput and transaction handling is almost always the limits of secondary systems such as storage.

    Without getting into too many details, modern DBMS technology running on fairly normal storage can easily handle thousands of transactions per second. This isn’t anything special – look up the numbers for RDS on Amazon’s AWS for example. Tens of thousands of transactions per second with dynamic scaling and fault tolerance are easily within the capacity of the AWS Aurora RDBMS;  with the key-value DynamoDB database, well over 100,000 operations per second are supported.

    Keeping it simple, suppose you need to handle a very large stream of transactions – say for example 30 million per hour. That’s a lot, right? Simple arithmetic tells you that’s less than ten thousand transactions per second, which itself is well within the capacity of common, non-fancy database technology. What applications come even close to needing that kind of capacity?

    The database isn't the problem, you might think, it's the application! OK, there is a proven, widely used solution: run multiple instances of your code. As many as you need to handle the capacity and then some — you know, kinda like microservices! It's more than kinda. Each transaction that comes in gets sent to one of what could be many copies of the code. The transaction is processed to completion, making calls to a shared database along the way, and then waits for another transaction to come in. Since all the code required to process the transaction resides in the same code instance, all the time and computational overhead of using the queuing system for moving stuff around among the crowd of services is eliminated. Both elapsed time and compute resources are like to be much better, often by a factor of 2 or more.

    OK, what if something extreme happens? What if you need more, and that somehow it’s your code that’s the barrier. Here the micro-services groupies have it right – to expand throughput, the right approach is sometimes to spin up another copy of the code on another machine. And another and another if needed. I talk about how to scale with a shared-nothing architecture here. Why is this only possible if the code has been re-written into tiny little slivers of the whole, micro-services?

    The micro-service adherent might puke at the thought of making copies of the whole HUGE body of code. Do the numbers. Do you have a million lines of code? Probably not, but suppose each line of take 100 bytes, which would be a lot. That’s 100 MB of code. I’m writing this on a laptop machine that’s a couple years old. It has 8GB of RAM in it. That’s 80 times as large as the space required for the million lines of code, which is probably WAY more than your system has. Oh you have ten million lines? It’s still 8 times larger. No problem. And best of all, no need to rewrite your code to take advantage of running it on as many processors as you care to allocate to it.

    I can see the stubborn micro-services cultist shaking his head and pointing out that micro-services isn’t only about splitting up the code into separate little services, but making each service have its own database. Hah! With each service having its own database, everything is separate, and there are truly no limits to growth!

    The cultist is clearly pulling for a “mere” tens of thousands of transactions a second not being nearly enough. Think of examples. One might be supporting the entire voting population of California voting using an online system at nearly the same time. There are fewer than 20 million registered voters in that state. Fewer than 60% vote, usually much less. Suppose for sake of argument that voter turnout was 100% and that they all voted within a single hour, a preposterous assumption. A monolithic voting application running on a single machine with a single database would be able to handle the entire load with capacity to spare. Of course in practice you’d have active-active versions deployed in multiple data centers to assure nothing bad happened if something failed, but you’d have that no matter what.

    Suppose somehow you needed even more scaling than that. Do you need micro-services then?

    First of all, there are simple, proven solutions to scaling that don’t involve the trauma of re-writing your application to micro-services.

    The simplest one is a technique that is applicable in the vast majority of cases called database sharding. This is where you make multiple copies of not just your code but also the database, with each database having a unique subset of the data. The exact way to shard varies depending on the structure of the data, but for example could be by the state of the mailing address of the customer, or by the last digit of the account, or something similarly simple. In addition, most sharding systems also have a central copy of the database for system-wide variables and totals, which usually requires a couple simple code changes.

    Sharding is keeping the entire database schema in each copy of the code, but arranging things so that each copy has a subset of all the data. Micro-services, in contrast, usually involve creating a separate database schema for each micro-service, and attempting to arrange things so that the code in the service has ALL the tables it needs in its subset of the overall schema, and ONLY the tables it needs. In practice, this is impossible to achieve. The result is that micro-services end up calling each other to get the fields it doesn’t store locally and to update them as well. This results in a maze of inter-service calling, with the attendant errors and killing of elapsed time. If all the code and the entire schema were in one place, this wouldn’t be needed.

    I am far from the only person who has noticed issues like this. There was even a list of problems in Wikipedia last time I looked.

    Making sure your application is scalable and then scaling it doesn’t arise often, but when it does you should definitely be ready for it. The answer to the question of how best to architect a software application to be scalable from day one is simple: assure that it’s monolithic! Architect your application so it’s not database centric – this has been a reasonable approach for at least a decade, think it might be worth a look-see? If you do have a RDBMS, design your database schema to enable sharding should it be needed in the future. Make sure each software team “owns” a portion of the code; if you work towards eliminating redundancy and have a meta-data-centric attitude, you’ll have few issues with team conflict and overlap.

    Do yourself and your team and your customers and your investors a BIG favor: stubbornly resist to siren call to join the fashion-forward micro-services crowd. Everything will be better. And finally, when you use the term “monolithic,” use it with pride. It is indeed something to guard, preserve and be pleased with.

  • The Map for Building Optimal Software

    So you want to build optimal software, do you? What’s “optimal” in software, anyway? Is it building the software that’s needed quickly and well, with no bugs? Is it building software that’s easy to enhance, adding new features – including ones you never thought of – with minimal fuss and bother? Is it building software that’s easy to scale endlessly with little trouble? How about all of the above, all at once? Yup, that would be optimal, sure enough.

    I’ve described in general terms about optimal software. Here’s a map, a specific example, of how to get there.

    Going to new places

    Let’s think about going places we haven’t been before, or taking routes that are new to us. What are the options for figuring out how to do it?

    If you’re talking with someone who is familiar with the place to which you want to go, you might ask them how to get there. If there are more than a couple of turns, you might try to simplify the directions or write them down. If you’re on your own, you might consult a map. If you’re computer-oriented you might use one of the on-line mapping programs. If you’re driving in a car, you might use a navigation system.

    No matter what you do, you’ll end up (let’s say) getting in a car and driving. When you drive, one way or another, you’ll be following directions and making choices of turns. Nothing happens unless you drive and to drive you need directions.

    It’s obvious that while you need directions, a fixed set of directions by itself is adequate only if nothing goes wrong – there are no accidents, no construction detours, no recent changes to the roads, etc. The minute there is any problem, you need a map or a live, map-driven navigation system.

    What you do when you look at a map, or what a navigation system does, is execute a generic direction-creating algorithm. Either your brain or a computer looks at the map, sees where you are and where you want to go, and figures out the sequence of roads and turns to get you there. Is there an obstruction? The nav system doesn't care — it just computes a fresh set of directions for you, based on where you are now.

    Here's an example. It shows two different routes for me to drive from my home to the wonderfully close source of some of the world's best home-made ice cream: Denville Dairy.

    163 Cedar Lake E to Denville Dairy Broadway Denville NJ Google Maps

    A direction-creating algorithm is a relatively small amount of code that is independent of the map that it uses. You may need to enhance it when different kinds of things are introduced into the map (for example, you decide to support avoiding toll roads or taking ferries), but once you’ve added the capability, it should automatically apply to all the maps you have.

    So “where” is the application functionality here? The ability to create directions is in a small amount of abstract code. This code accepts a reference to a map, a starting point, an ending point and perhaps some parameters, like whether to minimize distance or time or avoid toll roads. The actual directions themselves are drawn from the substance of the map. In this case,

    • what you’ve got is the map;
    • what you do to what you’ve got is create directions.

    Isn’t it interesting that most of the time and effort is creating the set of maps, without which there are no directions? And isn’t it interesting that the maps are data?

    Maps are:

    • Extensive
    • Subject to frequent updating and change

    An error in a map is bad, but should not “crash the program” – it should just lead to bad results, and should be easily fixed, without going into debuggers, single-stepping and other geeky things.

    The direction-creating program is:

    • Short
    • Infrequently updated
    • Unaffected by additional maps
    • Unaffected by changes to maps

    Best of all, the direction-creating program is unaffected by the driver not following the directions – the program just builds new directions to the destination from wherever the car happens to be.

    Errors in this program are crippling, but it’s likely that errors will be found early in the process, after which it won’t change much.

    Maps and writing optimal code

    So what does this have to do with writing code? Lots.

    A map (meta-data) is an efficient, compact, re-purpose-able representation of what the user cares about. It is truly Occamal, without redundancy. Each piece of knowledge you have about the world is represented in the map exactly once.

    A reasonably well-written direction-generating program is an efficient, compact representation of strategies for generating routes through the entire universe of possible maps. Each algorithm or strategy for generating directions should be represented in the program exactly once.

    Combined, the map and the direction-generating program are a pretty good template/metaphor for an Occamal program. Here’s the pattern:

    • You should make everything you possibly can into a “map” (metadata).
    • Abstract actions that cannot be reduced to metadata should be coded once, and should be “driven” to the largest extent possible by the metadata.

    The map to building optimal software is a simple idea: build the smallest amount of code you possibly can, and put as much information as possible into passive, declarative meta-data. That will get you to your destination safely and in the shortest amount of time without breaking laws.

  • Lessons for Better Software from Washing Machine Design

    The power of Occam-optimality, a.k.a. occamality, can be difficult to appreciate if your head is awash in myriad software buzzwords, and explaining it in software terms can make understanding it challenging to anyone unfamiliar with those terms. So it makes sense at this point to explain the core concept in a different context.

    Let’s think about the design of physical things, the kind of things that require discrete manufacturing, have bills of material, and so on, for example a washing machine.

    Capture

    If every section of the washing machine were designed by someone different, each designer may call for a particular screw here, or a particular composition of aluminum there, making his best judgment on what is the best to use. When you broke down the bill of material into a consolidated parts list, you may see two of this kind of screw, one of that kind, and a couple of yet another kind. It may be that the various screws need to be sourced from multiple suppliers. As far as the designer is concerned, the various screws are completely legitimate requirements. Each was chosen to have everything required to get the job done, but only to get the job done. The designer is probably proud, with good justification, of the care and effort he expended in specifying exactly the right screw for the job. When the design is complete, the washing machine will have a list of unique parts and designs and/or instructions for how to construct and/or assemble them.

    While the designers may be proud, everyone else’s jobs have been made more difficult and the overall expense of building washing machines has been increased. If instead the designers had been motivated to get together and find a way to use a single screw type that could be sourced from a single supplier, more screws would be bought from a single supplier in greater quantities, reducing both unit and shipping costs, and enabling all assembly points to be supplied from a single pool of screws. Only one type of screw driver would be needed, which would also help keep all the screw drivers in working order during manufacturing. Even the repair manual would be slightly easier to write and would be slightly shorter, and repair people would need only a single type of screw and a single type of driver, which would increase the odds that they would have what they needed to do a repair on a single visit. If the design were done in this way, the overall design would be virtually unchanged, but the parts list would be shorter – there would be a smaller number of unique parts, with each used more frequently.

    How about the designers? Instead of starting from scratch when they needed a screw, picking the “right” screw from the universe of available screws, which is large, they would agree up front on a screw that would meet all their anticipated needs closely enough, and then, every time they needed a screw, they would just check to make sure the pre-chosen screw was adequate to the job. This is a simpler job than selecting the “best” screw from a large selection, because you’re just applying a short list of disqualifying characteristics to the pre-selected screw. Moreover, you’re arranging your design as you go along (for example, the thickness of the plates) to match up with the qualities of the screw, making the selected screw very likely to be OK in each case. So the “shortest” (without going too crazy) parts list, the one with the smallest number of unique parts, clearly is the best design.

    Notice that the original design, the one with lots of types of screw types, would be defended by its designers as the “best” design, because they understood that the important thing for them to do was to create the “best” solution for each design problem they faced, considered in isolation. Let’s assume they did. But once the designers look at the whole problem, and try to pick the best design for the entire lifecycle of the washing machine, including sourcing, manufacturing and repair, it’s obvious that the different screw selections were incidental aspects of the washing machine design. The design could just as well have been embodied in one that had fewer screw types, and as we now understand, having fewer parts is better.

    Suppose there are a couple of established washing machine manufacturers. Suppose you wanted to enter the market with a superior product. If things worked the way they normally do, the earlier products are probably far from occamal. That means it's possible to design a washing machine with just as high quality as the ones on the market, but less expensive to build and easier to service. Everyone would like your product better than the existing ones. Cheaper to build, cheaper and easier to fix in a single visit; what's not to like? This means that, in addition to being a core design principle, occamality helps us understand and predict the evolution of products in a market, all other things being equal.

    In a virtually identical way, a program that has the smallest (within reason) number of unique “parts” is the best, for reasons that are very similar to the way that the best physical design has the shortest list of parts. It definitely helps the designers, and it helps everyone else even more. Just like with a washing machine, a program can be built, from the requirements all the way through, to have lots of unique “parts” and custom things, each of which may make sense when considered in isolation. But when you look at the whole software lifecycle, taking a view over the entire program and everything that will eventually be done to it, including later maintenance, change and enhancement, it becomes clear that designing it to contain the smallest number of “unique parts,” so that every “program concept” is defined in exactly one place, yields the best design.

    The parable of the screw can help you, your organization and your users avoid being screwed during software design. You’ll get there if you keep this principle in mind: always use the smallest number of unique “parts” that you can, and be willing to adjust your design to make the number even smaller. This may sound easy to you, or it may sound like an essentially trivial exercise in neatness. It is neither. It can be challenging in practice, and the implications of it are actually profound and far-reaching.

  • Experts vs Innovation New Book

    Experts and anointed authorities of various kinds, both academic and commercial, have been the front lines of resistance to innovation for centuries, up to the present. They are the firewall keeping what they consider to be rogue ideas outside the protected environments they oversee, protecting them from bad influences that their naïve but innocent charges might inadvertently adopt. It’s a good thing they’re on the job – otherwise things would be chaos and nothing would get done!

    This pattern is raised to a new level when the subject isn’t some specific business domain like healthcare, but the process of innovation itself. As you may have noticed, many organizations now have the expensive modern equivalent of “suggestion boxes,” departments devoted to fostering innovation in the organization, led by a Chief Innovation Officer. Government officials have gotten into the game, establishing centers for innovation, and “incubators” for startups. Eager not to be left behind, academia has jumped into the game, with august professors doing what they do best: pronouncing truths and activities designed to promulgate them.

    There was a time in my relatively innocent past when I was willing to give the experts a pass. Hey, how can you know everything? I know I don’t!  They’re probably just trying to keep their organizations from being taken down by harebrained ideas, and sometimes they fail to recognize a true innovation when it appears! I no longer believe that pleasant, forgiving fiction. They’re also not evil geniuses immediately recognizing a juicy innovation when it sniffs around the door, and stamping it out before it can start making changes. The truth is far worse: the vast, vast majority of them wouldn’t know a practical, effective innovation if it came up to them and slapped them in the face! See this and this for more.

    The bulk of front-line experts act this way to “protect” their organizations against scary change. They go to great lengths on multiple dimensions to assure that nothing upsets the status quo. Here is detail about the measures they take to prevent innovation, and simple methods to overcome the measures – which the experts are universally ignoring.

    But the elite of the experts are experts in entrepreneurship – people who are “expert” in enabling people who want to create and lead innovation to make it happen. These experts on innovation are like experts on being expert. We are definitely still in the middle of an “innovation” bubble, with everyone acting like it’s a new thing. In fact, it’s looking like less of a bubble these days, and looking more like something that’s going to stick around. Here’s some information about the bubble and how we got here.

    I’ve seen so much of this over so many years, and been so disgusted with the useless wisdom of experts, that I’ve put together some preliminary thoughts, drawn from experience and observation, about how innovation happens. See this.

    Imagine my surprise when I read an article about entrepreneurs that actually made sense! I'd never heard of the guy, Carl Schramm.  It appears from the article that he knows a bunch of stuff about entrepreneurs and innovation that matches up pretty well with my observations, but is actually backed by … real data! OMG! One of my initial shocks was learning that he was a real professor at a real university, even with a PhD, but that … he had worked as an entrepreneur! How is that possible? How did he manage to slip by the super-strict requirements that prevent anyone who actually knows something from experience becoming a Professor?? Maybe it helped that he had been the head of the Kaufman Foundation, the largest foundation devoted to the study of entrepreneurs and innovation, and that instead of just doling out grants, he did real studies to gather real data. What an idea. You think maybe the people who run Departments of Computer Science could get inspired? Sorry, forgive me, you caught me dreaming the impossible dream there…

    I’m not finished reading the book yet, but here it is:

    Burn business plan book

    As you might guess from the title, he talks a lot in the beginning about that near-universal requirement for getting innovation funded, the dread business plan. He trashes it. Vigorously and effectively. No, he doesn’t trash this or that business plan, he trashes the very idea that business plans are both essential and good. He’s right! For exactly the same reason (he doesn’t say this, I’m saying it) that project management in software development is not just brain-dead, but a positive impediment to getting good software done!

    If you are ready to learn about a different and better way to be an entrepreneur, check out this book.

  • Here’s How the FDA Can Reduce Medical Device Costs While Improving Healthcare

    The FDA wants to keep us safe. They want the drugs we take to be what they’re supposed to be, and they want the medical equipment used on us to be safe and without fault or error. We all want that!

    However, the way they choose to achieve the goal for the software that is an essential part of most medical devices is deeply flawed, and leads to huge expense with only a small number of companies willing and able to follow the FDA’s regulatory regimen for software. The net result is medical equipment and software (which is increasingly a key component of medical equipment – think MRI machines) that is wildly expensive and uses seriously outdated technology.

    There is a simple, easily understandable reason for this horrible state of affairs, which the grandees of the FDA refuse to acknowledge or even understand. The root of the problem is that they don’t understand software. Which doesn’t stop any of them from being certain they can regulate it. Because of this inexcusable ignorance, they take the regulatory approach developed over many years for drugs and manufacturing and apply it with only cosmetic changes to software. Safety is safety, they probably say to themselves. We’ve proven our approach for drugs; why start from scratch for software?

    The mistake made by the FDA, along with nearly all the hard-charging graduates of MBA programs, law schools and bureaucrats everywhere is in thinking that the process of manufacturing is like the process of building software, except not as visible or physical.

    In manufacturing, you have a factory with raw material arriving, being processed in a series of steps, with quality checks along the way, and emerging as finished goods at the end. The important thing is to check the quality of the raw materials as they enter and the results of each step of processing to make sure it’s up to snuff. At the end all you need is a cursory quality check, because so long as everything is done right along the way, the result is probably good.

    Similarly, they think, in software you have a set of requirements, with lines of code and software components being produced along the way, with careful unit testing being performed at each stage, and more tests as the components are woven together. The end product is subject to more testing, but the important testing has already been done. The idea is that quality is designed in.

    This method for building software is exactly what, in gruesome detail, the FDA requires. It’s spelled out in highly detailed regulations. Sounds good, right? Why would anyone want crappy software, particularly when it comes to our health?

    The trouble is that this whole way is thinking is based on a blatantly false analogy.

    What they think is that the manufacturing process of converting raw materials to finished goods is just like the process of creating lines of code and combining them into a finished software product. People even talk about “software factories,” and how important it is to churn out quality code, on time and on budget. Still sounds good, right?

    Here’s the problem: a factory that produces finished goods, whether they’re drugs or cars, is making copies of a design that’s already been created and tested. In the drug development process a drug is created and validated through testing. All that’s done in the drug factory is assure that the copies that are made of the already-designed-and-proven drug are exactly and only what the drug creators intended.

    Designing and building a new piece of software is like the drug development process, not the drug manufacturing process. The software is created for the very first time, with changes made along the way. The software equivalent of a drug factory is trivial: it’s taking a piece of executable software and making a copy of it. There is a universal software “factory” that works on all software: the copy utility. It’s what happens when you go to the Apple or Google software store and download the software you want. The download makes a bit-for-bit-100%-accurate copy of the original software for your use. That is software “manufacturing!” There’s even a universal quality check – a checksum is always incorporated in the original prior to copying that the receiver can check. The checksum tells you whether the copy is perfect, just like all the drug manufacturing quality checks do, only with software, it’s easy. Yes, because software is different. Here is more about software factories.

    What the FDA regulations do is specify and control in gruesome, expensive and time-wasting detail the process of building the very first, original copy of the software – like creating the drug in the first place. This is a complete and total waste. The methods and processes of building software are constantly evolving, with the most innovative companies, the ones that actually create new software, at the forefront. These companies have small, focused teams who crank out great software, and do it quickly. They use what can be called “wartime” methods of building software.

    The FDA should scrap its mountain of software regulations and replace them with a simple set of regulations that achieve the same goal, more effectively. I describe this in detail here. The new regulations amount to something like “We don’t care how you build your software, but its your responsibility to assure that the software performs its stated job each and every time, 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.”

    This of course, shifts the entire burden onto the software creators – as it should. Inspections are no longer required. Employment at the FDA should go down, but of course, since it’s the government, it probably won’t.

    Changing the medical software regulations in this way will unleash a wave of innovative, low-cost medical software. It will be as though runners were required to carry 100 pound backpacks and walk on stilts; as soon as they can dump the pack and use real running shoes, just watch them set records! They will be a race with each other to see who can cross the finish line in style the fastest, with no stumbling along the way.

  • William of Occam is the Inventor of the Method for Building Optimal Software

    Lots of people would like the credit for establishing, once and for all, the core, immutable principle of optimal software design/architecture – the method for measuring which, among an infinite number of embodiments of software requirements, is provably the best among them. I am one of the crowd that would love to take credit! Alas, I and my competitors have been beaten to the punch, by a mere 700 years or so, by a guy named William of Occam.

    As it turns out, the software crowd is, as usual, late to the party: loads of luminaries in other fields have recognized William’s achievement, viz., Occam’s Razor, for the indispensable concept that it is. Various software folks have been nipping around the edges of it, for example with the DRY (don’t repeat yourself) principle that’s gotten some attention. But they haven’t grasped the fundamental, touches-nearly-everything, deep nature of the Razor. Too bad! Crappy software continues to be churned out by the ton by people who are enthralled by false idols, convinced they’re on the righteous path toward software excellence, when in fact they’re doing something else, words for which should not be used in polite company.

    William of Occam (ca. 1285 to 1349) was an English logician and Franciscan friar.

    330px-William_of_Ockham_-_Logica_1341

    He is credited with formulating a principle that is already widely applied to various aspects of computer systems. In those areas of computing to which it has been applied, it reigns supreme – it unquestionably supplies the most fundamental, relevant and optimal understanding and solutions to the relevant problems, so much so that the people involved don’t think about it or question it.

    However, 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. Even while the practitioners call themselves "computer scientists," which is something that none of them are.

    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, inapplicability and generally what we don’t like about software. Once the principle is understood and widely applied, I expect it will become the un-discussed and undisputed standard for how software is built, just as it has in the other areas of computing to which it has been applied.

    What is this amazing standard? It’s simple. I mean literally simple. That’s what Occam’s Razor is all about.

    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.

    Another way of expressing this is that all redundancy, of any kind and in any way, should be eliminated from a piece of software. This often requires writing imperative code to implement any and all abstract actions, and to create largely declarative meta-data to specify everything that is specific to an application. The meta-data, of course, should also have no redundancy; this is normally achieved by use of multiple inheritance with override. See this for more.

    To be extremely brief, the reason why eliminating redundancy is good is that practically everything that happens to a piece of software is that it is enhanced, altered, bug-fixed or otherwise modified. Creation happens just once; everything that follows is growth and change. Implementing change of any kind to a program takes the least effort with the least risk if everything is defined in exactly one place – once you’ve found the place, you make the change and you’re done. Among the infinite universe of programs solving the same problem that work, the speed, cost and risk of change is the overriding virtue, both in technical and business terms.

    Thanks to William of Occam, I can’t claim to have invented the core principle of software, and the way to express the measure of goodness for software. William has me beat by over 700 years. Thanks a lot, Bill! Lots of people have applied Occam’s Razor to lots of tough things with optimal success, even in things closely related to software, such as information theory. Way too late again. About all I can do is mess with his name and make up a term that expresses goodness in software. Here it is: I propose that a piece of software can be measured by its “Occamality.” The more “Occamal” it is, the better it is. And I propose that Occamality is strictly correlated with the extent to which there is no redundancy of any kind in a program, which is almost always strictly correlated with the program being at the high end of the hierarchy of abstraction.

  • How to Pay Down Technical Debt

    When we look at a body of software, how do we judge it? Clearly, there are strong opinions on this subject – but there is no general consensus on the standards by which a body of code should be judged! This is shocking and unacceptable!

    For most normal people, i.e., people who aren’t software developers, software is “good” if is doesn’t crash and pretty much does what you want most of the time. What more could anyone want? Well, how about changing the software. This is one of the BIG things that makes software different from pretty much anything else in our experience. How often do you try to make changes to your car in the same sense that you change software? The answer is never.

    There are standards for nearly everything in life, certainly for things that are built by engineers and other technical people. How is it that, not only are there NO standards for what constitutes “good” software, but the fact that there are no such standards is not decried, and no one appears to be sheepish or unapologetic about admitting it – because they’re never asked to admit it. The subject never comes up – not only in “polite company” but even in “impolite company,” i.e., among programmers talking quietly among themselves.

    “Ya know,” someone might say, “we tell them there’s technical debt. Sounds fancy, right? Anyone ever been asked what it means? They seem to think that WE know what it means, and that’s good enough for them. I wonder how much longer we’re going to be able to get away with it?” Someone else says, “Forever, man. This has been going on since before we were BORN, ya know? Unless word somehow gets out, and how could it, we’ll die without anyone being the wiser. Good thing.”

    I wish programmers did have quiet dialog among themselves like the one I made up above. But they don’t, at least that I’ve ever heard. There’s nearly always someone who has strong opinions about what software should look like internally, and of course the current body of software doesn’t measure up. So there is agitation and there are threats about the awful future consequences of failing to rein in the spreading disease – soon! RIGHT AWAY!! – unless the transformation is authorized.

    Then the re-writing death march starts off, with various sections of the code slated for repair, renewal or even flat-out re-write. What is the target? It varies. Favorite criticisms include that the code is spaghetti, it’s a monolith, it’s not structured according to some set of object-oriented principles, it’s written in some obviously inferior language, there aren’t components, there are no services, micro or otherwise, and on and on. The solution is obvious to the converted, and value to be achieved by the solution is so obvious that it’s hardly worth stating.

    Is there any value to be gained by the clean-up of “technical debt?” Maybe. But often, nothing really changes except a lot of time has been spent with no improvement to the business. No one can point to a proof or a study or a clear historic pattern demonstrating the effort is worth making.

    This is a shame, because there is a clear pattern of success for a method of organizing and/or re-organizing code for business benefit.

    Let’s start from the business benefit. Of all the ways a piece of software could be written that performs the same function, which is the best in business terms? I’m assuming here roughly the same level of performance, etc.

    Tick, tick, tick… Think about it!

    When you come right down to it, no one cares about today’s software doing today’s things for today’s customers – so long as it works and performs reasonably well. What matters is simple, and everyone knows it: it’s the next request by an important existing customer, and more important, the next potential customer who is balking about things they need that aren’t there, the time, cost and risk to implement the software, etc. In other words, what matters about today’s software is TOMORROW’s changes, whatever they may be – we can suspect, but we won’t know until we know them!

    Software people have talked forever about things like “architecting for change” and various fantasies that mostly go poof when the harsh wind of reality rushes at them.

    There are exactly two rarely-discussed aspects of code that position it optimally for the widest possible range of unanticipated changes and the needs of installation:

    • A minimum of redundancy in the code – anything you want to change can be changed by going to one place
    • To the largest extent possible, particular things the application does are defined in meta-data instead of code, with the result that the code is smaller and more abstract with minimal redundancy — and that any change can more likely be made by changing meta-data, which is quicker and safer than changing code.

    That’s it! See this for more.

  • Why the Equifax Hacking Disaster Wouldn’t Happen at a Car Dealership

    The 2017 Equifax data breach is in the news again because of the recent indictment of four Chinese government hackers for committing the break-in. How did they pull off such a feat? From China? As it turns out, Equifax’s defenses were so pathetic that a couple of bright nerd wise guys anywhere could have done it.

    By contrast, the Equifax hacking could not possibly happen at a car dealership – unless the dealership were run by government and corporate cybersecurity experts. Understanding why that’s so tells you everything you need to know about the expertise of the experts.

    The 2017 Equifax hack

    First, a quick – VERY quick – review of the Equifax hack. Equifax has websites. One of them is just for people who want to dispute their credit rating. This particular site was run on a computer with software that had a serious flaw, allowing a skilled person to get past the normal consumer web pages and run other programs on the computer. The flaw had a fix that could easily have been installed, but because of a series of bungling and delays, the fix wasn’t installed for months.

    The flawed software on the Equifax site was widely used. The fact of the flaw and the fix for it were publicly available. Anyone could have read about it and fired off a search for websites on which the patch correcting the flaw had not been installed. Someone found the Equifax site had the issue, exploited the flaw, and ran a couple programs without doing much else.

    More than a month later, the flaw still unpatched, someone got into the Equifax server again and started “looking around.” They found an unencrypted file with names and passwords. They used the information to log in and got access to a series of databases that had Equifax customer information. For 76 days, they used the databases like any authorized user would, and issued queries that returned a great deal of customer information, which they stored in files. They encrypted the files and used standard programs to ship the files out of Equifax, presumably to themselves.

    Hacking the Equifax-run car dealership

    Suppose someone had tried the equivalent of the Equifax hack at a car dealership. The hacker would have physically walked in the service entrance, along with the other existing customers. The hacker knew that many doors had a security flaw in their lock that had not been fixed. The exact nature of the flaw had been publicized, and any reasonably skilled person who knew about doors and locks could exploit it. Once inside the customer service area of the dealership, the hacker looked for the “employees only” door, and quickly saw that it had not been fixed. The hacker walked up to the door, fiddled with it for a couple minutes, opened it and walked in. In a real car dealership, the employees would have immediately noticed a strange person and challenged him, politely showing him out. In the Equifax-run car dealership, the intruder is ignored.

    Once in the employee section of the dealership, the hacker wanders around, poking into lots of things. Finally he walks into the finance department and wanders some more, again unchallenged. He notices a row of file cabinets against the wall, and figures there must be valuable information in there about customers and cars, with all sorts of details like names, addresses, driver’s licenses and who knows what else. But he sees the cabinets are locked. Darn! So he looks around some more and spots some keys sitting on someone’s desk. Even though it’s daytime and people are working at the desks, on the phone, etc., no one says a word when the intruder picks up the keys, walks over to the file cabinets, and tries one key after another until finding the one that works. He opens the cabinet, takes out a handful of folders, walks over to the copy machine, and makes a copy of every document in the handful of files. He then goes back to the file cabinet, returns the originals, puts the keys back on the desk, and walks out of the building the way he came, holding a big pile of copied pages in his arms. Unchallenged.

    The next day, the hacker returns to the Equifax car dealership and goes through the same drill – goes into the employee-only section, then the finance department, uses the keys to open another drawer, makes copies and walks out, all without a single one of the many employees working there saying a thing. He does this day after day for 76 days.

    Finally, someone notices that there’s supposed to be a guard by the employee entrance checking everyone – there always used to be one! So a guard is put there again. The guard notices that the daily visitor carrying lots of paper doesn’t look like everyone else – he’s carrying big piles of paper! The guard doesn’t stop the visitor, but reports to his boss; meanwhile, the visitor notices the guard, figures the jig is up, and stops coming.

    More than a month later, the Equifax-run car dealership’s bosses finally let the word out that they had been hacked.

    The Equifax breach vs. the car dealership

    You already know that nothing even vaguely like the Equifax breach could have taken place in a car dealership. In the dealership, people have common sense and are dealing with physical things, while at Equifax, everything important happens on computers that are in locked rooms, with software that is invisible to nearly everyone, doing things that most experts barely understand, managed by people who have no real knowledge of software using management methods taught in business schools by professors who are ignorant of software, and following rules and regulations written by lawyers and bureaucrats. What can you expect but madness and chaos??

    What went wrong at Equifax

    Equifax’s cybersecurity methods followed regulations and industry-standard practices, with all required certifications. The result of these methods, when executed perfectly, is security that is worse than that of retail stores or libraries. In the end, Equifax made exactly two mistakes – but each mistake mattered because of further bungling and the failure of ordinary follow-up checks.

    • The web server patch, the start of the trouble. The patch was announced on March 7, 2017.
      • What they did: On March 9, administrators were told to apply the patch. They didn’t. On March 15 a scan was run that was supposed to detect unpatched systems. It didn’t work. It wasn’t run again or fixed. Result: the patch wasn’t applied until August or later.
    • The bad traffic detection box. A great deal of web traffic is encrypted. Equifax had installed a box at the “edge” of their system to stop all incoming encrypted traffic, unencrypt it, make sure nothing “funny” is going on, report suspicious activity, and re-encrypt and send along each message. It’s like a traffic stop for incoming traffic.
      • What they did: encryption works with keys, and keys expire periodically. The key used by the box expired 10 months before the hack started. Equifax failed to renew the key, and the traffic-stop box was set up to let all traffic through without checking unless it had a valid key. No one noticed until July 29, 2017, when the certificate was finally renewed. When the traffic stops started again, an administrator noticed suspicious activity, and sounded alarms bells.

    I’m going to add this fact, just because I find it amusing: the Chief Security Officer was a music major, Susan Mauldin. She had degrees from U Georgia in music composition. Her background was scrubbed from the internet as soon as the scandal broke. Of course, you don’t need a college diploma to be excellent at software, IMHO. But in this case…

    What car dealership management would do at Equifax

    People who run car dealerships aren’t usually thought of as geniuses, but part of succeeding in business is protecting your customer records, and everyone involved takes care to do that and do it well. All that was required for Equifax to have avoided being hacked was to do the software equivalent of what every sensible car dealer employee would do. Obviously, such common sense is beyond the ken of the high-paid professionals and certified experts at large places like Equifax. Here are the main things that would be done if car dealer people replaced Equifax management.

    • Recall/repair notice.
      • The second a car dealer hears about a recall/repair issue for cars, they jump on it. Similarly, just exercising common sense, if they learn that the restricted entry system to the employees-only area has a fixable flaw, they would get it fixed immediately. No excuses. Car dealer management would have seen to it that the flaw was patched, and checked.
    • Guard duty.
      • At the car dealership, there is extra security around the finance department, which holds all customer data. During working hours, there is always someone alert to the door, challenging anyone entering who shouldn’t be there. Off-hours, there are deadbolts on the metal doors, along with an alarm system that has motion detectors and cameras, which gives an immediate alert on any sign of trouble. If the alarm system drops its constant, real-time communication with the monitored center, electronic alerts are sent, so the problem can be immediately fixed. The room and its data are NEVER left unprotected.
      • With car dealership management, the encryption key on the traffic checker wouldn’t have been allowed to expire. Instead of setting up the traffic checker to stop checking unless it had a valid key, car management would have made it set off alarms so it could be fixed right away.
        • When car dealership management learned that only incoming traffic was being checked, they would have pitched a fit. What? You’re just letting anyone waltz out with anything?? They would have installed a system to stop and check outbound data traffic before letting it out.
    • Keys
      • Car dealership management would never allow the file cabinet keys (user names and passwords) to be lying around for anyone to pick up.
    • Employee behavior monitoring.
      • Car dealership management would make sure anyone opening a file cabinet was a person authorized to do so, and that their actions were reasonable. When they found out that anyone could open a drawer and pull out and copy ALL the files in that drawer, they would have been enraged. They would have immediately put a software system in place to ring a bell and prevent anyone from taking more than a single file.
      • While at Equifax the only real checks were with people as they were coming in, after which they could do anything without being checked, car dealership management and employees know that everyone has roles and acts in certain ways – and that everyone is responsible for noticing unusual behavior and questioning it. With car dealership people in charge, the software equivalent of such monitoring for “normal” behavior would have been implemented and strictly enforced, with immediate shut-down of a user if they stepped outside the bounds of their normal actions.
      • Car dealership management understands that audits need to be done, and that auditors need broad access to customer files. This is the ONLY time mass access to customer files would be permitted, and ONLY under the watchful, suspicious eyes of multiple dealership managers, who would ASSURE that all files would be replaced WITHOUT BEING COPIED.

    Expert recommendations for Equifax

    The “experts” have had a wide-ranging set of advice for Equifax. Equifax has spent over $1.4 billion dollars making largely useless “improvements” to its security. I haven’t read ANYWHERE recommendations of the kind of changes any sensible car dealership would make, as described above.

    Here are some of the leading recommendations of what Equifax should do to improve their cybersecurity:

    • Change management reporting, processes and procedures.
      • I love this one. It’s a commonly-recommended “cure” for cybersecurity ills.
    • Encrypt all customer data
      • This is a favorite, and widely recommended. It is USELESS. It would NOT have prevented the Equifax hack!! Why? Easy: once the hackers were in and were using employee user names, they just issued SQL queries against the database. If the data on the disk, the database un-encrypts the disk blocks, processes the SQL query, and returns UN-encrypted data. Otherwise, the data can’t be used!
      • Encrypting data on disk is like having locked, strong metal file cabinets. But authorized people still need access. Therefore, file cabinets have drawers and keys. When you open the drawer, the data is easily accessed. Encrypting data “at rest,” as they say, protects only against the hackers who somehow get close to the cabinet and drill into it from the side or bottom. Who would do that? It’s easier to steal the keys or break the lock!
    • Create more silos
      • The nice-sounding theory is that breaking everything into silos would limit a break into just one silo. But far from being a solution, silos were actually part of the problem at Equifax – applying the delayed software patch required writing memos and asking multiple people to do things, when in a uniform environment, a single script could have updated everything.
    • Change the reporting structure
      • Because when you change who reports to whom, everything changes, right? In Equifax’s case, the Chief Security Officer reported to the Chief Legal Officer, while the Chief Information Officer reported to the CEO. “That’s the cause of the breach!” shrieked an amazing number of pundits!
      • What there should probably be is two Security Officers:
        • A CSRO, Chief Security Regulation Officer, who reports to the Chief Legal Officer. This person is in charge of the massive, ever-changing, lawyer-created body of regulations that are supposed to assure Security. There are severe penalties if you fail to conform to the regulations, which require loads of reports, processes, documents, etc. But they have little to do with real security.
        • A CRSO, Chief Real Security Officer, who reports to the Chief Technology Officer. This person is in charge of making sure that real security is performed, in spite of the regulations.

    Conclusion

    Computer software and systems are hard to understand, a problem made worse by the fact that they’re literally invisible. You'd think that would be OK, since for example even fewer people understand quantum physics and we’re OK in physics. The trouble is, the people doing physics really do understand it, while the people doing software in general, and cybersecurity in particular, are faking it – without even suspecting, in spite of the mountain of evidence to the contrary, that they’re faking it.

    The result is that government agencies, powerful consultants and weighty experts recommend more of the same medicine that created the problem, without a shred of recognition that it was their own rank stupidity that caused the problems to begin with.

    For more perspective on this subject, see these posts.

    Note: this post first appeared at Forbes.

  • How to Build Applications that can be Changed Quickly

    Nearly everyone who talks about fast and reliable application building seems to talk about the process (Agile etc.) and/or a couple architectural things (object-oriented, micro-services, etc.). From what I can tell, these haven’t led to any break-throughs in application velocity or predictability. However, it’s clear that there are methods for high-velocity application growth. A wide variety of small, motivated groups have re-invented them over the years. I have had the privilege of observing these groups and their methods, and seen the impact when they add or drop velocity-aiding methods.

    Here is an overview of some of the methods I’ve seen used. The improvements can range from cutting time in half to whole number factors, things like turning weeks into days or in some cases hours.

    Forget requirements, focus on change

    The normal requirements process starts with the often non-technical people who have a need. The need can be expressed directly, or through refusal to buy/use a product, which gets the attention of sales and marketing people. There then ensues a process of requirements gathering and refinement. Wire-frame UI’s may be involved. Finally, the requirements are ready for engineering, and away we go on hopefully not too many “sprints.” This is an “outside-in” approach.

    Speed is achieved by taking an “inside-out” approach – instead of focusing almost exclusively on requirements, center your efforts on the code and what it can do or easily be changed to do today to go in the direction of the requirements. Take steps to change and add to the existing code to meet the unmet needs. Do this in small steps, getting feedback at each step. When you’re done, go back and “clean up” the code to eliminate redundancies as much as possible, to make the next change as easy as possible.

    What this does is ground the changes in the existing code, resulting in the changes and additions being smaller than they otherwise would be. As a additional benefit, it usually results in a greater uniformity of both the code and the interfaces (UI and API) to the code.

    Minimize the customization and optimization of the code and UI

    When product people think about a new process that has UI, they usually try to do a good job, understanding all the details and nuances involved. The result of this sophistication is often requirements that are finely adapted to the particular function being performed. What’s wrong with this, you may wonder? One problem is that this approach ends up taking longer to built and results in more code. More important is the users – the less someone has to learn to use a new feature, the more quickly and easily they’ll be able to use it. Familiarity is incredibly important. Which means, among other things, that literally using rarely changing templates to generate interfaces will both make any new interface element recognizable and easy to learn, but also lead to the least amount of code changes to get the job done.

    This means that the fineness and sophistication of product people can be a problem. The more time they spend on a subject and the more they think and reflect on it, the worse the temptation is likely to get to do something other than just crank out another instance of a familiar pattern.  Resist!

    Avoid planning and designing for change and future requirements

    When starting a project, accomplished software professionals often insist on a period devoted to design or architecture, in which the overall technical approach to the project is determined. When things go wrong later, inadequate or insufficient up-front design is often cited as the reason. “We’re gong to insist on being able to do it right next time, so this won’t happen again.” But all too often, projects slip and slide regardless of any up-front design work.

    Generally, up-front design time is actually counter-productive. The reasons are simple: you spend time “designing” when you could have been building; the result of the design is often building for anticipated change, which takes time; when the anticipated change doesn’t happen and unanticipated change arrives, the code added because of the design almost always makes things harder.

    None of this happens when you build incrementally and strive toward uniformity, eliminating code redundancies and moving functionality from code into meta-data.

    Wartime software

    The methods I have described as wartime software maximize speed and efficiency of building new software that meets business needs. See here for details. Generally, the methods include:

    • Eliminate overhead
    • Avoid things resembling “project management”
    • Optimize for speed instead of expectations
    • Use production environments for testing instead of sand boxes
    • Use comparison QA; avoid test-driven development, unit testing and test scripts
    • Minimize the use of documents, meetings and other internal overhead
    • The main architectural value should be speed and scale
    • Avoid technical fashions

    Move up the mountain of abstraction

    When you think about code and methods, the main values should be the elimination of redundancy in both data definitions and code, and migrating functionality from code into meta-data. See this and this.

    The other methods described here are important for moving quickly, and are complementary to this one. But moving up Abstraction Mountain is the most powerful of the methods, often yielding qualitative improvements.

    Conclusion

    This is a short post, and the methods are described briefly. In a different world, each topic here would be at least a course in the Computer Science curriculum, and in a couple cases multiple books. I don't claim anything I've said here is fully described. But every single item has been proven in practice by many groups over many years, in different ways, always resulting in better quality software that meets business needs being built dramatically more quickly than other methods could possibly have achieved.

    My goal here is simply to provide a short list of the main methods for fast development in a single place.

  • The Iowa Caucus Software Problem Exemplifies Widespread Software Management Problems

    Everyone who’s even vaguely in touch with the headlines knows there was a problem getting results from the Iowa caucuses – a problem blamed on a software app built to automate reporting voting results. No one, including the maker of the app, disputes there was a serious software problem.

    Most of the commentary has focused on steps that should have been taken to assure that the app worked better than it did. The Wall Street Journal quoted various “experts” who stated – authoritatively, no doubt – that “testing could have prevented” the problems.

    What’s not being said is the emperor-has-no-clothes “secret” – our society is irrationally obsessed with software, and acts convinced that getting new software to perform some function that is now getting done with older software or without software will make things better, be worth the trouble and have no downside. Otherwise sensible and experienced people continue to ignore the ongoing, rolling disaster of software building and deployment, and blissfully welcome new software nightmares, as though there’s no chance that anything could go wrong. The Iowa Democrat caucus face-plant is just the latest of a decades-long parade of software disasters. To make it explicit: I'm using this highly visible event as an occasion to illustrate a general, widespread problem; it has nothing to do with Democrats or politics.

    The 2016 Caucus Software

    Both Democrats and Republicans hold Caucuses in Iowa. Each party sets its own rules and changes those rules as it sees fit. They even do the voting a bit differently. Nonetheless, the parties cooperated to have a single piece of software that would service all their needs. They jointly announced this in the Jan 31, 2016 Des Moines Register:

    Capture

    They also had phone backup in case of software problems. The net result is that the Democrat Party chairman announced final results:

    Capture

    The software wasn’t perfect, of course – software never is. But it got the job done:

    Capture

    The 2020 Caucus Software

    In the summer of 2019, the Iowa Democrats decided that, instead of upgrading the software that worked for them last time, they would pay for brand-new software to be built by a tiny, brand-new firm run by a non-programming History major who’d had a role in the tech of the 2016 campaign for Hillary Clinton. New firm. New software. Has to work out of the box, with over 1,700 people using it for the first time. No problem, right? That’s what the chair of the DNC proclaimed just hours before the caucuses opened.

    Many people at the caucuses had trouble using the software, and in the end, it just didn’t work – it wasn’t able to load the results it captured from the people who were finally able to use it into the DNC reporting database. An analysis shows the kind of amateur-hour flaws you'd expect from the kind of group that built it.

    Of course they forgot or ignored, like most people do, the train wreck of so many high-visibility new software unveilings, illustrated well by the ACA software releases of 2013 such as the one in Oregon I discuss here.

    The Curse of Technology

    Technology can be a wonderful thing. I’m grateful for the good things it delivers. But even relatively simple, physical technology can have massive problems. Did you know that 3,613,732 people have died in motor vehicle accidents in the US alone between 1899 and 2013? In 2016, 37,461 people died, as the carnage continues unabated. Just to put that number in context, the total number of US military deaths in all wars starting with the Revolution is well under half that number.

    Does this surprise you? Here’s an example: during the entire period of the Vietnam war, the US had a total of 47,424 military deaths. During EACH year in the period 1966 to 1973, there were more US traffic deaths than the total for the war, with a high of 53,543 traffic deaths in 1969. You know which category of numbers people paid attention to.

    The problems with computer and software technology massively dwarf those of physical technology, by huge factors.

    Physical bank and stage coach robbers make for good visuals and press. One of the most famous was Willie Sutton, who spent decades in jail for having gotten about $2 million from all his hold-ups over many years. Let’s introduce computers and software to make things better! Sure. Banks lose over $10 Billion a year due to computer-driven credit card fraud alone! Banks vs. banking software? No contest.

    Loads of people in the industry are promoting the latest software fad, for crypto-currency, like Bitcoin. It’s supposed to be super-secure. Sure. It turns out to be even worse, as the mounting software failures and losses demonstrate.

    What all of this means is that once a piece of software does what it’s supposed to do, in production and at scale, no sensible person even thinks about replacing it with a whole new application. The reality is that most of our bedrock software systems took years to build, are often decades-old – and continue to work solidly and reliably.

    An excellent example of this is the body of COBOL code produced by the small software company Paysys. When I was CTO of the company, in the late 1990’s, it ran over 150 million credit cards, including for Citibank, GE Capital and other name brands. The company was bought by the world’s largest credit card processor, First Data, and an incrementally evolved version of the same code now runs over 600 million cards, more than any other piece of software. The code is nearly 30 years old! It’s written in “obsolete” COBOL! There have multiple major attempts to re-create it using “modern” technology, sometimes with efforts taking years and costing tens of millions of dollars. Failures, every one.

    The reality is that software is hard to build and get right, even today, after decades of time to figure it out. If we were as good at building bridges as we are at software, no one would dare drive over one. The big tech companies, for all their glittering reputations, are lousy software builders. When they try to build something new, they usually take years and end up failing – which is one of the reasons they acquire so many software companies, companies that in many cases have somehow managed to build software that they couldn’t. Here are details about Facebook’s ineptitude. If it's so hard for tech giants, chock full of super-bright nerds, why should anyone expect brand-new software written by a tiny group of amateurs to perform well the first time, with no testing or training, and in a national spotlight?

    Building Software is different than building other technologies

    People make decisions about software that, if it were any other technology, they would never make. In fact, they would consider those decisions to be beyond stupid.

    Suppose you needed to get 1,700 people to an important public event from scattered places. While they didn’t all have to arrive at exactly the same, they had to be there within a couple hour window. Without fail. What would you do? You might consider asking a couple of established limo companies with fleets of reliable cars and experienced drivers to get it done. If a couple people insisted on driving themselves, you’d make sure their cars were OK and they had a backup plan. You might arrange for some car-pooling, or bring some people to a central spot and arrange for an experienced bus service with professional drivers. You might do any number of things.

    Let’s further suppose you’d done something like this once, but when you did it again, you wanted to do some important things differently. Suppose you needed to make two trips on the same day. You would probably make some changes to what you did last time, while adjusting for whatever didn’t work perfectly before, right?

    There are lots of things you wouldn’t even think of doing. Would you do any of the following?  Design, build and distribute brand-new vehicles for doing the transporting? Contract with a tiny, new company with no real track record to design the vehicles from scratch, not even modifying an existing model that works? Distribute the vehicles with no real test-rides? Give them to each of the 1,700 people to drive themselves? Given that the vehicles are new, not built according to standards, expect the new drivers to drive themselves with no training and no help? When the people have trouble driving, have no help available? When the vehicles break down, have no back-up plan to get the job done? When the disaster drags on for days, still be unable to fix it?

    No, I don’t think any person would consider making these kinds of decisions with physical-world technology. The very thought would be ludicrous. But this is exactly what happened with the 2020 Iowa Caucus software! Endorsed and supported from the top of the DNC, and not questioned by any of the Iowa leaders!

    Conclusion

    There is a problem with how we think about and build software. A big problem. It’s nearly universal, and shared by normal people and supposed software experts. What happened at the 2020 Iowa Caucus technology is exceptional only in that it was so highly visible, which is why I use it as an example. The insane decision-making process that took place there takes place every day, from the way normal people and organizations work with software to the way tech giants and software so-called experts work.

    The small groups of people who build software effectively and well are largely ignored by experienced managers and organizations. But these are the ones who are most likely to create amazing new bodies of software that change industries, before their software is absorbed and subsumed into the larger organizations who try to avoid breaking it too badly.

    The mainstream thinking about software, both by managers and by software experts, is badly flawed. Things won't get better until fundamental things are changed.

  • The Three Dimensions of Software Architecture Goodness

    In my work on Wartime Software, I describe the methods used by small groups of smart, motivated programmers to compete with large, established groups using standard software techniques – and win. I haven’t invented those methods; I’m simply collecting, organizing and describing what such groups of software ninjas actually do.

    Similarly, after observing the internal structure of many bodies of software over a long time, patterns emerge about the internal structures that yield competitive advantage, and tend to take market share. These internal structures are a kind of continuum rather than an either/or: a group that is farther along the continuum of goodness I’ve observed has a substantial competitive advantage over any group whose software is more primitive in the continuum. This pattern is so strong that you can see it play out with many companies competing over a long period of time.

    The patterns are fundamentally simple, but rarely discussed among programmers or in the literature – and not taught (to my knowledge) in Computer Science departments. Using the patterns, it’s possible to rank any piece of software along three independent but conceptually related dimensions.

    The dimensions are:

    • The code. The not-good end of this axis is code that has a great deal of redundancy, and the good end is code that has no redundancy.
    • The data. The not-good end of the axis is data that is defined and/or stored in multiple places, and the good end is data that is uniquely defined and stored.
    • The meta-data. The not-good end of the axis is a software system with no meta-data, and the good end is one in which most application functionality is defined and controlled by meta-data, and can be changed by editing it with no code changes. I often think of this as the vertical dimension.

    These dimensions are closely related conceptually, but in practice aren’t necessarily linked. Nonetheless, in practice, movement towards the good end of any dimension encourages and helps movement towards the good end of the others.

    Why should anyone care about dimensions of software architecture goodness?

    It’s an abstract idea. It’s new to many people. It’s a tough addition for managers whose heads already are chock full of barely understandable buzzwords and acronyms. Why pile on more?

    Simple: investments in moving software towards the goodness end of the dimensions is HIGHLY correlated with shorter times, lower costs and lower risks of meeting the evolving needs of existing and new customers in a highly competitive market. The correlation is clearly demonstrated historically, and incremental progress yields immediate benefits in sales and business satisfaction. There is no single thing a software group can do that has greater impact on fast, low-cost and trouble-free delivery of existing and new product features to customers.

    I know these are bold claims, particularly in an environment that swirls with buzzwords for software. Everything will be better once we start programming in Golang, like Google! Our teams will work better and our software will be scalable once we re-organize using micro-services! We’ve got to automate testing and move to test-driven development! We have to add Kanban to our Agile environment, and hire a certified SCRUM master! These subjects and more have passionate adherents and are widely implemented. But none of them yield the promised results, which is part of why there’s such a merry-go-round of methods becoming fashionable, only to fade quietly into obscurity or ho-hum, nothing’s changed but it’s just what we do.

    Details of the Dimensions

    Data

    The data dimension is the most widely understood and practiced of the three. I hope everyone who can spell “relational database” is familiar with the concept of a normalized schema – the whole point of which is to assure that each piece of data is defined and stored in exactly one place. But the concept of a normalized schema applies strictly within the bounds of the DBMS itself – there is no widely used term or concept for a truly central definition of data, including inside the code.

    Is having fewer, less redundant, more centralized definitions a good idea? You bet. This is largely why the RAILS framework for Ruby rapidly grew to widespread use. It had nothing to do with the design of Ruby or its object-orientation – it was all about the RAILS framework and it’s central DRY principle; DRY = “don’t repeat yourself.” The idea was/is simple: data definitions in RAILS are created in a central place – and then applied by the framework both in the DBMS schema and in the data definitions in the code to access the data. To change a data definition, you change it in the RAILS definition, and it changes it in both the database and the Ruby code.

    It’s important to note that the data dimension in my definition encompasses data wherever it appears – program files, schema files, anywhere.

    Code

    The code redundancy dimension is much less understood and recognized for its importance. But the value of reducing code redundancy is easily understood: when you need to make a change to a program, how many places do you have to go to make the change? The answer any appropriately lazy programmer would like is “exactly one place.” The programmer finds the place, makes the change, and all is good. As you add code to a system to make it do new things, often you end up repeating or creating, perhaps inadvertently, variations on existing themes in the code. When you’re done, what’s the best thing you can do to make the next change as easy as possible? Eliminate the redundancy. That’s it! Objects, layers, components, services and the rest don’t matter. Redundancy matters.

    Meta-data

    The third dimension is meta-data. Having no redundancy in the meta-data dimension is important, and is often achieved by measures such multiple inheritance hierarchies and links. But the most important thing is this: to the maximum extent possible, application-specific behaviors of all kinds should be defined in meta-data rather than lines of code. Goodness in this dimension is measured by growing meta-data. Over time, decreasing code redundancy is achieved by increasing the size, extent and power of the meta-data.

    This evolution directly powers business benefits for the simple reason that meta-data can be changed and augmented quickly without creating a new version of the code and without fear of introducing bugs into the code. In the end, you end up with something like Excel: the source code never needs to be touched, while supporting endless variations of spreadsheets, with no programming skills required. When you make a mistake in a spreadsheet, you may not get the result you want, but Excel doesn’t crash.

    Conclusion

    Wartime Software is a collection of techniques that have evolved to build software quickly, and to win in a software-fueled business.  People who practice some subset of this collection of techniques often find themselves moving towards the goodness end of the software architecture dimensions as they rapidly cycle their code, since every small step along any of the three dimensions helps them move more quickly and satisfy emerging customer needs more rapidly than the competition. It’s one of the most powerful tools in the Wartime Software arsenal.

  • How to Design User Interfaces for Heavily-Used Software

    There is lots of knowledge about software user interfaces — standards, models, experts and the all rest. But there's a problem: there is no difference, the way things are now, between designing a UI for someone using a piece of software for the first time, and someone who uses it over and over. This results in astounding waste of time for the heavy users of software. It's long since time to fix this glaring hole in UI theory!

    Most UI’s are built to optimize the initial experience of the person using it. The assumption is made that the person is using the software for the first time and needs to have a good experience. Otherwise the user will reject the software, not use it again, and it might feel bad! So the software needs to be “user-friendly.”

    But what if the people using the software use it for a good part of the day, every day? If we can make them just 10% more efficient, then that’s worth something. So what if they need some training at the beginning? And the fact is, in many cases we’re looking at way more than 10% improvement. In large categories improvements of 50% are available, and in some large-scale cases, substantial whole-number factors of gain.

    Since everyone thinks they know how to build user-friendly software (if only more of it were!) and since most programmers don’t even think about high-use, high-productivity software, here are the main principles of building a user interface whose users will spend a great deal of time using, and who want to get more done in less time:

    • Arrange the work to minimize movement
      • The first and most important step is to eliminate is anything that takes the human’s eyes or hands away from the computer. Paper is a prime example – having an image of paper on the screen is vastly more productive than having a physical paper.
      • Given that eyes and hands are on the computer, the next step is to eliminate the use of the slow input device – the mouse or touch pad. Everyone loves the mouse. They think requiring its use is the most user-friendly thing you can do. But we’re talking about productivity here, and in any productivity race between mouse and keyboard, the mouse is a sad, distant last. So with the possible exception of logging in and out, just lose the mouse. Don’t compromise or be “nice” about it.
      • Now that all inputs are keyboard inputs (and they are, aren’t they???), reduce the number of keystrokes to the bare minimum. You would be amazed, when you count keystrokes (yes, you should actually count keystrokes; yes, you), how many can be eliminated in the average application.
      • Finally – don’t laugh – minimize eye movement. It’s not the time, it’s the attention.
    • Arrange the work to minimize thought.
      • Sometimes, like when people are writing something, they just need to think. That’s OK.
      • But any other kind of thinking is just a waste of time. Think about your own thought-free actions; I hope typing is a good example. When you have to look at the keyboard or think about it at all, instead of just typing, what happens to your rate of typing? Does it improve as a result of the thought? I didn’t think so.
    • If some training is needed at the beginning – OK; if training is needed on an on-going basis, you are probably making the user do things the computer should do – instead of training, automate.
    • Embodying domain knowledge is really tempting. You should make your system so that the users don’t need domain knowledge. It’s made particularly hard because you typically need domain experts at the beginning to make sure your system is sensible. They want to see the way they think about the problem embodied in the system.
      • A good example is working with health care forms. There is a huge amount of domain knowledge involved in doing this right. But the vast majority of this knowledge can be put into the system, so that the people end up just doing things that only people can do.
    • Arranging the UI and the people so they know what they’re doing and why is really tempting – resist that temptation! The more your users just do their work, focusing just on productivity and accuracy, leaving the rest to the “system,” the better off everyone will be.
      • A prime example of this is QA. In most systems, the users know whether they are doing the work for the first time or checking someone else’s work. This knowledge is built into the user roles and the queuing system. It’s true that in some cases this can’t be avoided, because of the nature of the work. But you’re well advised to avoid it, if you possibly can.
      • What does role hiding look like? An example is in heads-down data entry. In the early days, experienced people would look at what was supposed to be typed, look at what was actually typed, and check for errors. It turns out that it was faster and more accurate to simply have the “checker” enter the data as though for the first time – and it always was the first time they were entering it. Then the system would compare the results, and flag an inspection or a third keying to resolve the conflict. This came to be called “blind double-key entry,” and remains the gold standard for productivity and quality in the industry.
      • Why does role hiding work? When someone knows what someone else thought the outcome or result should have been, it influences them, one way or another, and it takes them time. It’s like when you suspect a teacher of giving biased grades or you want to know how good a food is. You get the most objective results by giving the tests to second teacher for grading because the (anonymous) other teacher got sick (or something), or you give the food for testing without labels of any kind. Remember the famous tests of Pepsi vs. Coke? Coke drinkers would always prefer Coke when it was labeled as Coke – but when two colas were unlabeled, most would prefer Pepsi, even the Coke loyalists.

    Building a UI that optimizes the productivity of the people who use it is a new and different way thinking for many software folks. But it's well worth pursuing — the results speak for themselves, and the professionals who use the UI will appreciate being able to get their work done in less time.

  • The Progression of Abstraction in Software Applications

    This post describes a little-known concept for understanding and creating software architecture that small groups use to defeat large, powerful incumbents and nimble competitors. It is one of a small number of powerful, repeating patterns that help us understand and predict the evolution of software. Understanding these patterns can help entrepreneurs direct their efforts; if they do it well, they greatly enhance their chances of success. Understanding the patterns can also help investors choose to invest in groups that are walking a path to success.

    Evolution of Applications Towards Abstraction on a Platform

    One of these patterns is the stages that applications naturally evolve through on a technology platform. Each step or stage brings a big increase in the power of the software, decreasing the effort and increasing the speed and effectiveness of being deployed to meet customer needs.

    A category of software applications may well get “stuck” at a particular stage for a long time, sometimes even decades. During this time, the software may appear to move forward, and of course the marketing people and managers will always put things in the best possible light. But it’s always vulnerable to being supplanted by a next-stage version of the functionality.

    While there aren’t clear lines of delineation between the stages, it’s nonetheless useful to understand them roughly as:

    • Prototype. A hard-coded body of code.
    • Custom Application. Does a job reliably, but most changes require changing source code.
    • Basic Product. The code now has parameters, maybe user exits and API’s. Real-life implementations tend to require extensive professional services, and the cost of upgrading to new versions tends to be high.
    • Parameterized Product. The level of parameterization is high, with interface layers to many things outside the core code, so that many implementations can be done without changing source code. There may be some meta-data or editable rules.
    • Workbench Product. A large portion of the product’s functionality has migrated from code to editable meta-data, so that extensive UI, workflow, interface and functionality changes can be accomplished via some form of workbench, which could be just a text editor. The key is that the details of application functionality are expressed as editable data, meta-data, instead of code. Nonetheless, all fundamental capabilities are expressed in highly abstract code.

    As a body of code goes through this sequence of abstraction, it is increasingly able to meet the needs of new customers and changing needs of existing customers, with decreasing amounts of effort, risk and changes to source code. At the same time, the more abstract a program, the more functionality is expressed as data that is not part of the software itself, a.k.a. meta-data, and the more the software implements generic capabilities, as directed by the meta-data.

    The pattern applies both to individual bodies of code and to collections of them. It applies to code built internally for an organization and to code that is sold as a product in any way.

    I defined the stages above as a convenience; in reality, the categories are rarely hard-and-fast. A body of code could be given a big transformation and leap along the spectrum, or it could take a long series of small steps. One body of code could remain stuck with little change in abstraction, while other bodies of code doing similar things could be ahead, or progress rapidly towards abstraction.

    The Driver of Abstraction Evolution

    In biological nature, competitive pressures and external change appear to drive evolutionary changes. Similarly, when we look at categories of software, if little changes to make the software change, it doesn’t change – why take the trouble and expense to change software that meets your needs or the needs of your customers?

    In reality, someone always seems to want changes to an application. A prospective user would gladly use the software if it did this, that or the other thing. A current user complains about something – it’s too slow, too hard to use, too complicated, or it just doesn’t work for X, Y or Z. How often does a piece of software not have a “roadmap?” If it doesn’t, it’s probably slated for retirement before long. Brand-new software is rare. The vast majority of software effort goes into making changes to an existing piece of software.

    How much time and effort is needed to change a particular body of software? That is the key touch-point between techies and business people. This is the point at which the level of abstraction of the application comes into play. Regardless of the level of abstraction of the application, the “change” required either has been anticipated and provided for or it has not.

    • If the change has been anticipated, the code can already do the kind of thing the user wants – but not the particular thing. Doing the particular thing requires that a parameter be defined, a configuration file changed, a template created or altered, workflow or rule changes made, or something similar that is NOT part of the program’s source code. This means that the requirement can be met quickly, with little chance of error.
    • If the change has not been anticipated, then source code has to be changed in some way to make the change. The changes required may be simple and localized, or complex and extensive – but the source code is changed and a new version of the program is created.

    This is what the level of abstraction of a software application is all about: the more abstracted the application, the more ways it can be changed without altering the source code and making a new version of the program.

    This is the fundamental driver of applications towards increasing abstraction: as changes have to be made to the application, at some point the technical people may decide to make the change easier to make in the future, and create the appropriate abstraction for the kind of change. This may happen repeatedly. As more complex changes are required, the program may just get more complicated and more expensive to make further changes, or more sophisticated abstractions may be introduced.

    While historically it appears that outside forces drive applications towards increasing abstraction, smart programmers can understand the techniques of abstraction and build an application that is appropriately abstract from the beginning. Similarly, the abstracting methods can be applied by smart programmers to existing bodies of code to transform them, just because it's a way to build better code and meet ever-evolving business requirements.

    Conclusion

    The hierarchy of abstraction in software is one of the most important concepts for understanding a specific piece of software, or a group of related software. Over time, software tends to become more abstract because of competitive and business pressures, or because of smart programmers working to make things better. The more abstract a piece of software is, the more likely that it can respond to business and user demands without modifications to the source code itself, i..e., quickly and with low risk.

    The hierarchy of abstraction is certainly a valuable way of understanding the history of software. But it is more valuable as a framework for understanding a given piece of software, and the way to evolve that software to becoming increasingly valuable. It is most valuable to software developers as a framework for understanding software, and helping them to direct their efforts to get the greatest possible business impact with the smallest amount of time and effort.

  • The Fundamentals of Computer Automation

    The principles underlying computer automation are clear and strong. They account for most of the automation we see. They tell us clearly what will happen, why it will happen, and what the benefits will be. What the principles do NOT tell us is who will first apply automation to what process in what sector.

    Understanding the principles lets you predict the rough order of the sequence of automation.

    The principles are extremely simple. Perhaps that's why they're rarely stated and appear not to be taught in schools or understood by practitioners. So much the better for people who want to innovate and win by automating!

    The Principles

    You can probably guess the principles of automation from the definition of the word: "automate" means to do by machine or computer what a human would otherwise do.

    At core, there's really a single simple principle:

    • Replace time that a person would have spent with work done by a computer.

    The core principle is demonstrated by a before-and-after comparison: the principle requires that human time/value doing whatever activity is being automated, net of the investment in the computer hardware and software, is reduced after the addition of the computer and software. Lots of words, same meaning: apply the computer stuff, and there's less total human time/effort.

    Expanding on the replace theme, "replace" means anything that reduces human time to do something:

    • Replace time that a human would have spent with work done by computer; REPLACE!
    • Reduce the amount of time spent by a human; REDUCE!
    • Arrange the human's time more efficiently, eliminating waste; RE-ARRANGE!
    • Decide Who does What work, How and Where they do it; RE-ORGANIZE!

    That's it! 

    This notion of what software was REALLY about struck me quite early in my career. The thought was simple: the ultimate purpose of most of the software I wrote is to replace humans. The thought made me uncomfortable. But after a while, I connected the thought with all the rest of the mechanization and industrialization in society for hundreds of years. A new machine is valuable only to the extent that it somehow reduces the total amount of human labor to reach a given result, everything taken into account! This was true for the Jacquard Looms to which the luddites violently objected in the early 1800's, and the same principles are at work today with computers, resisted by modern-day luddites.

    In other words, computers are the next step in a long sequence of people figuring out how to get stuff done with less effort by themselves and/or other people.

    Here are some simple examples:

    REPLACE

    Replace what humans do with computers doing it is the core principle of automation. E-mail is a super-simple example, since computers automate the entire process of delivering the result of typing to another human being, eliminating the many steps involved in doing it physically. The replacement can be low-level and mechanical, like delivering email, or it can be high-level, like the work of deciding who should do what work in what order.

    REDUCE

    Electric light is a pre-computer example, since it reduces all the time required to, for example, deal with the oil lamp, and replaces it with flicking a switch. A modern example is spreadsheets, which automate the time people used to spend making calculations with adding machines.

    RE-ARRANGE

    Introducing chat into customer call centers eliminated huge amounts of wasted waiting time, so that phone operators could handle chat when they weren't on the phone.

    RE_ORGANIZE

    Routing certain kinds of calls to the optimal customer service person (Who does What work), giving them scripts and hints.

    The Principles apply to Manual and Mental work

    At the start of automation, the computer and software automate work that it's pretty plain that people are doing. As it gets more advanced, a couple interesting things happen.

    1. Once the work is done by computer, it sometimes happens that better ways of getting the work done are possible. This is the same principle we see in mechanical flight: even though all birds have wings that flap, airplane wings don't flap. Instead of flying the ways birds do, engineers have figured out of the core principles of flying and reflected those in airplane design. Similarly, human work is often first translated to computer automation simplistically, and later rebuilt without reference to the human origins.
    2. Once computers are a significant part of the landscape, computer people figure out valuable things to do that have little to do with what humans have done in the past, though this is uncommon.

    The Principles are recursive

    At the beginning, getting computers to do things is incredibly labor-intensive. As time goes on, some people look at the work humans do to get computers to do things — and automate the automation process! Yes, the very programmers whose job is to put people out of work can be put out of work by computers. And on and on.

    The Principles applied to human interaction

    We can see the principles in action in the sequence of changes that have taken place in normal interactions between human beings.

    Prior to automation, the only way humans could communicate was by voice, and by being in each other's physical presence. Here are the major automation steps that have taken place:

    • Writing a letter.
      • Automation is making and acquiring paper, pen and ink, and transporting letter
      • Eliminates the travel time of the sender and/or receiver
    • Publishing books, newspapers.
      • Automation is printing and distributing the books or papers
      • Eliminates the travel time of all the receivers
    • Telephone
      • Eliminates the travel time for the parties to get together
      • Eliminates the time spent writing and reading, and the delay in transmission of prior methods
    • Mobile phone
      • Eliminates the need to travel to a phone to make and/or receive calls
    • Voice mail
      • Eliminates the requirement that the receiver be available when the caller calls, for those cases when it's applicable
    • E-Mail
      • Writing a letter with near-real-time delivery and the ability to read when ready, like letter reading and voice mail.
    • Chat
      • Like email, only with a different interface, making it better for real-time, written exchanges, with minor delays acceptable.
    • Scripting
      • In customer service centers, reduces training, reduces human error, and reduces the time to produce an optimal answer to a question.
    • VRU, chatbot
      • A recorded and/or machine-generated party in a conversation.
      • Applicable to all of the above methods.
      • Eliminates a human giving repetitive responses or messages.

    This all seems obvious, right? Like we know all this stuff, what's new?

    For the steps above that are computer-based, what's interesting is that the technical capabilities were often in place considerably before they were brought into production. The gap was usually not decades-long, like it has been with more esoteric technologies. And in each case, knowing the technology and this fundamental principle could enable you to predict that the automation would be built and deployed.

    Conclusion

    If you want to predict the future of technology and evolution, study the evolution of software and the fundamental principles that drive its application. The principles are obvious! But they are nonetheless rarely discussed or applied.

     

  • Luddites Smashed Looms then and Resist Automation today

    The few people who are familiar with the term "luddite" think that a luddite is an unfortunate but stupid person who fights against advancements that make things better, while clinging bitterly to their crappy, low-end jobs. "Luddites" in this common view, are uneducated, progress-preventing people who need to be moved to the side so that society can be improved.

    The reality is that, in most cases, luddites were highly skilled craftsmen performing difficult and challenging jobs. It's not that much different today. Luddites are often highly educated professionals and managers who are convinced they bring value to their complex jobs every day The reality is that there are luddites everywhere. Who wants to have their job disrupted? Who wants to be told that their expertise is no longer needed, and that a machine or software system can do a better job?

    Stepping back

    This notion of what software was REALLY about struck me quite early in my career. The thought was simple: the ultimate purpose of most of the software I wrote was to replace humans. The thought made me uncomfortable. But after a while, I connected the thought with all the rest of the mechanization and industrialization in society for hundreds of years. A new machine (or program) is valuable only to the extent that it somehow reduces the total amount of human labor to reach a given result, everything taken into account!

    The replacement of humans by machines was extremely clear to the luddites, the secret society of workers whose jobs were being eliminated or reduced to unskilled labor by the increased use of Jacquard Looms. The movement was named after one of the first people to smash a loom, Ned Ludd: 375px-Luddite

    The core of the movement was actions to destroy the job-killing looms that automated and de-skilled the worker's jobs: FrameBreaking-1812

    This is particularly interesting and relevant to computers eliminating human labor. No one thinks of what could be the modern equivalent of workers smashing the looms that threaten their jobs. An ironic twist is that the revolutionary Jacquard looms were mechanical computers — they executed a "program" that was encoded physically, enabling them to execute flawlessly elaborate patterns in the woven cloth.

    Luddites today

    Yes, there are luddites today. Lots of them. But they're not so crass as to pick up big sledge hammers and smash the looms that threaten their livelihoods. They're more subtle, and far more supported by elite society than the original luddites ever were. They're not even seen as resisting change — they're seen as highly trained professionals that we're so grateful to have. Very much the way that the skilled craftsmen displaced by machines were seen by themselves and most of their contemporaries!

    So who exactly are these modern luddites? They include many of the elite, highly-paid professions that ambitious young people strive for.

    • Lawyers. A growing fraction of lawyers are under attack by automation. The pain is shown by declines in law school graduate hiring, the growth of firms such as Legalzoom, and growing outsourcing to low-wage locations. The trend has been growing for at least 20 years. I have personally seen the resistance of lawyers to automation efforts.
    • Doctors. The ready-to-be-luddite feelings are strong here, though automation is still in its early stages. Doctors increasingly feel like they work in a non-stop assembly line, with patients questioning their statements because of Doctor Google. With insurance companies increasingly questioning and challenging their actions and clinical decision-tree software chomping at the bit, doctors can feel like targets. While hiring remains strong, automation efforts continue to gain strength.
    • Software engineers. It seems only fair that the people who drive automation should have their jobs automated. This isn't in the news, but in fact there have been many waves of software job elimination — masked by strong growth in newly emerging technologies. I have run into many programmers over the years who jobs were eliminated; some of them have left the field, and others slide into management positions, managing people doing jobs they barely understand. For example, during the 1970's there was an explosion of jobs building operating systems for minicomputers. Minicomputers are long gone, along with the diverse operating systems needing to be built. A long trend is skills degrading — today you can build a functioning web site without programming, while years ago building software with a sophisticated user interface required serious software effort.
    • Actors and musicians. We have more visual and musical entertainment available than at any time in human history. But the vast, vast majority of it is recorded and replayed! The vast majority of musicians, for example, were employed making adequate, best-available performances at local places. The number of such jobs is a tiny fraction of what it once was because of recordings. All the supporting jobs are greatly reduced as well. Even jobs in movie theaters have cratered, since people watch on personal and home devices.

    What will become of all those people and jobs? The answer has been the same for hundreds of years: there will be great pain for the individuals involved, but overall, the wealth of the population will grow. A clear example is agriculture. At the time of the American revolution, over 90% of the population was involved in agriculture. One step at a time, those jobs were automated, so that in 2019, only about 1% of the US population was employed in agriculture. Yet there's food enough for everyone, and jobs that didn't exist back then.

    Conclusion

    As a person who has been directly involved in automation for over 50 years, I have seen the jobs I've had and the skills I've acquired become obsolete over and over again. I've also seen or been part of eliminating through automation many jobs, a surprising number of them highly skilled jobs. An early one was the capable engineers who ran the oil refinery in Venezuela in the late 1960's whose jobs were eliminated by the software I worked on at the time — the software just did a better job than the engineers could possible do! I describe this here.

    Luddites can and often do postpone their replacement by automation. But they lose in the end. I don't see an end to this process any time soon.

  • Getting Results from ML and AI 6: Fintech Chatbot

    While the success patterns laid out in the prior posts in this series may seem clear in the abstract, applying them in practice can be hard, because nearly everyone who thinks or talks about AI (these sets over overlap very little, sadly) takes a different approach.

    https://blackliszt.com/2018/03/getting-results-from-ml-and-ai-1.html

    https://blackliszt.com/2018/04/getting-results-from-ml-and-ai-2.html

    https://blackliszt.com/2018/04/getting-results-from-ml-and-ai-3-closed-loop.html

    I previously discussed the application of the principles to healthcare, with specific examples:

    https://blackliszt.com/2018/08/getting-results-from-ml-and-ai-4-healthcare-examples.html

    I've discussed the application of the principles to fintech, with a focus on anti-fraud:

    https://blackliszt.com/2019/12/getting-results-from-ml-and-ai-5-fintech-fraud.html

    In this post, I'll show how things can play out with a stellar example in fintech chatbots.

    Computers talking with People — Using People Language

    The idea that computers should talk with us in our language rather than people struggling to learn computer talk has been around nearly as long as computers have. The earliest "high level languages" like FORTRAN and COBOL were each attempts to let people use English-like language for telling a computer what to do. They were baby steps, and people quickly decided that computers can and should do better. This thought was one of the earliest practical drivers towards Artificial Intelligence (AI) in general, and Natural Language Processing (NLP) in particular. 

    One of the acknowledged milestones towards a computer that can talk like people was the work of Terry Winograd at MIT during 1968-1970. He created a talking robot, SHRDLU, that could talk about and act in a special world of blocks: Blocks

    SHRDLU could have conversations about the block world that amazed people at the time. Here's an excerpt, see this for more.

    11

    I was at college at the other end of Cambridge at the time, heard about SHRDLU, and got even deeper into the AI work I was engaged in at the time as a result, for example this project. SHRDLU was wonderful, but I wondered about and worked on how to represent knowledge and actions internally. After I graduated, "everyone" was convinced that "talking computers" were going to burst on the scene any day now. A couple decades passed, and nothing.

    Talking Computers Today

    Here we are, 50 years later, and things have definitely advanced. We have Alexa and Siri, and in banking we have Bank of America's much-promoted Erika. But in many ways, these programs remain primitive, and are far from being able to understand context and sequence the way people do.

    One of the reasons for this is that human language understanding and generation is really hard. Another is that the vast majority of people who work on the problem are thoroughly immersed in the other-worldly vapors of academia, in which publishing papers and gaining esteem among your fellows are the all-consuming goals — to the exclusion of building products that do things that normal people value and, you know, work.

    The State of the Art in Chatbots

    The founders of the Oak HC/FT portfolio company Kasisto come from that world, and also from the industrial labs of Stanford and IBM that try hard to commercialize such fancy stuff, with products like Siri as results. The Kasisto people are obviously exceptional not just in their field, but in their drive to make code that does real things in the real world. If that's your goal, there is exactly one standard for measurement: what people do and say.

    That's the background of the first remarkable thing about Kasisto, which I learned when I probed details of their process. Pretty much everyone who deals with AI/ML builds and builds in the lab, until they have achieved amazing things that they're ready to roll out … which promptly belly-flops in the real world. We'll do better next time, promise! Kasisto works the way everyone should work, but practically no one does — people first!

    This means they get in the middle of a huge number of human-to-human chat sessions, building and tuning their software first by human judgment, but increasingly by machine judgment. They "try" to answer the human's question, and just as important, they rate their ability to answer the question appropriately. After tens of thousands of tests, their ability to respond like a human would improves — and just as important, their self-rating of how well they're likely to do improves as well.

    As their answers and the associated self-ratings get good, they start actively playing a role in the live question-answer flow. For exactly and only the human questions for which Kasisto is "confident" (using an adjustable threshold) it will answer well, its answers go to the human — but are still routed to a human for double-checking, with a frequency that goes down over time.

    There will always be questions that are beyond the capability of the Kasisto bot, but so long as it is "self-aware" of which ones, the customers continue to get great service, with an ever-shrinking fraction of the questions being routed to humans for answers. If Kasisto can handle 95% of the questions, this might means that instead of a staff of 100 to respond to customers, a staff of 5 could do the job.

    This way of thinking is far removed from the typical academic head-set — and I've just given a couple highlights, there's actually much more where that came from!

    Beating the Pack

    What I've already described enables Kasisto to deliver chat results to customers that are far superior to anyone else in the field. But the overall head-set and people-first technique, combined with some true tech smarts, leads to further things.

    The first thing is context. All the other chatbots are lucky if they can give reasonable answers to isolated questions. The combination of human-first, good tech and practical methods enables Kasisto to not only answer isolated questions far better than others, but follow-on questions as well — questions that make no sense by themselves, but perfect sense when taken in the context of an interactive sequence. As a simple example, consider this:

    "How much did I spend last month?"

    "How much of it was on restaurants?"

    "How about the previous month?"

    That's a simple one for humans, but way beyond what other chatbots can do. Why? The computer has to figure out that "how much of it" means "How much did I spend on restaurants last month?" Not to mention, handling multiple languages; performing transactions; making changes and selling products.

    While Kasisto started with consumer banking, it's already added high-value functionality for treasury, business banking and more. The key is: Kasisto, unlike everyone else in the field, didn't just start selling into those applications — they followed the laborious but effective, bottoms-up, people-first method of exhaustive training and seamless integration with humans doing chat.

    Conclusion

    Kasisto is an excellent example of the incredible results that can come from following the path briefly outlined in these blog posts. You would think with all the talk about AI and ML, and the all efforts and announcements, that highly capable systems would be popping out all over. They're not! That makes the few that follow the success patterns I've discussed here all the more impressive.

Links

Recent Posts

Categories