Though it’s a years-old news story, Volkswagen produced a diesel-powered car which was designed to pass emissions checks although, under normal operation, the vehicle produced emissions which would not have met an acceptable threshold. The company threw a newly-minted engineering middle manager under the bus for cars being shipped with this emissions-check-defeating feature. This abuse of power placed responsibility for a clear flouting of emissions laws directly on someone who was not in a position to drive design or business decisions. The emissions system in cars typically goes through a number of hands, and checks before mass production. This means coordination would have been necessary between many teams to produce a vehicle which would violate US law.
There is a sense of click-bait, and one of the most common forms is n-best lists. These are the 10 best basket weaving solutions on the market. Here are the 5 best practices of highly successful cat herders. Vampires HATE these 3 things do them to stay safe in your parking garage. They are right there. You almost want to click them to read more, right?
In the software development social sphere, the most pervasive n-best lists are things like “the 5 best skills to have as a software developer”, or “the 3 most important things you’ll do for your software development career”. Every time I see these lists, I can’t help but ask “are these really the most important things?”
Frankly most of the time, these people are putting a list together of the things which saved their butt today, or this week. To that end, I can’t blame them. On the other hand, claiming these things are the best ever seems a little disingenuous.
Over the past year or so, I have been diving into a lot of social science information. I did a six-month crash course on foundational linguistics topics. I’ve been reading about cognitive science. Lately, I’ve been reading about cognitive load theory. What I’ve come to believe is, the reason people don’t know where to put the new great thing they learned is, they don’t exactly know what way it helped them.
Bikeshedding1 – that never-ending debate about a material disagreement – is so commonplace in the software industry we actually have parables about it. What’s more, I have actually seen people launch into meta-bikeshedding where they actually end up in an argument about what the original bikeshedding was about.
This is part 4 of a multi-part series on naming things. part three will be useful
Names are pesky little beasts. No single name exists without context1. This can be a disadvantage when names are unclear, abbreviated, or accidentally related to the surrounding context. On the other hand, if we understand that all names exist within some context, we can more carefully select the intention both of the name and the surrounding context for the name itself.
Long names can be a smell and, as we explored in a previous post2, we can do a little back of the envelope exploration and uncover a possible theme for the work being described in our source. Once we have identified a thematic word3 or phrase, we can lift that aspect from the current name and use it to contextualize the source at a higher level.
In every brownfield project I have ever worked on – and I have worked on a fair few – there is a common pattern I find. Developers either name their variables incomprehensibly, or they avoid using variables at all. Chains of function calls and expressions which stream across the screen and off the right side are the norm.
This is in no way an indictment of the developers who were working on the code. In fact, I assume they applied their knowledge in the best way they knew how at the time they were developing. Often developers are not armed with the knowledge they need to write stable software, or coherent source code.
Eric Evans addressed this problem from one side in his book, Domain Driven Design, as he talks about going to where the users are to uncover the way they talk about the work they do. He defines things like bounded context, and ubiquitous language (which is an extension of a lexicon), and late in the book he covers ways to incorporate those discoveries into the software being built.
The challenge is, there is an assumption of incremental discovery, however, incorporation can happen late. This means software can either languish in development limbo as discovery is done, or it can go off the rails early, which makes it difficult to recover.
What we really need is a tool right now which helps us iterate toward a better solution while we do the context and language discovery which needs to be done.
In a previous blog post1 I talked about an article claiming that reading source code was not like reading natural language. The original post referred to an article from “Science Daily”2, however there were far too many details missing, so I could only speculate on what the research said, how it was conducted, etc.
Last night I looked up a writeup on the original study3, and I found it to be rather disappointing. Though I haven’t used an functional magnetic resonance imaging (fMRI) device for any purpose, let alone the purposes of mapping brain activity, I can (and will) use other evidence to propose the founding notion of their study was flawed. This foundational flaw, in my opinion, invalidates the discovery which was done.
While analyzing and editing source code, much of the work to be done is rather straightforward. Many business applications are data stores with a user interface so a non-developer can manage the data.
Even these applications, however, introduce certain small complexities which tend to muddy the water. A subset of users need product codes to be handled in a way the system didn’t originally account for. Certain segments of the software must serve two distinct user types, which lead to very different workflows. A particularly common issue which arises is, sometimes data is incomplete or corrupted in a way that breaks the application.
All of these scenarios, and a multitude of others, require consideration of the rules which drive the system, and the choices which must be made to satisfy users. Source code which handles varied options, or things which must be is dealing in modality1.
In the past 25 years, or so, it has become popular to consider high-level structure of programs in chunks defined by a group affectionately referred to as the “Gang of Four”. They wrote a book called “Design Patterns”1 which laid out common patterns for solving well-understood problems in software.
There are many more patterns than those laid out in “Design Patterns”, but the idea still remains the same. The design starts, typically, at the module, or class level and goes up from there. Occasionally design will start at a function level, when the programming language allows for independent functions, but this is rather uncommon.
On the other hand, when looking at source code line-by-line, people often fall back to naming as a primary design strategy, and follow the convention of “put your variables as close to their use as possible”. Though this strategy makes sense contextually, since you can see the variable declared and defined near the use of the value.
Where we land when following common rules of thumb and patterns is a mix of large chunks of design, and small clusters of variables followed by use. This code is arguably better than code in which no design choices were made. However, we are overlooking a critical aspect of communicating in our code.
This is part three of a multi-part series on naming things. Part two will be useful1.
When looking for the right name for something you can end up with a pretty long name. In part 2, we looked at capturing conditional context by extracting a simple expression, but the name was pretty long.
Long names can be problematic for code scannability. We can work to move the most important words to the front of the variable name, but once a name gets long enough, it begins to contribute to the wall of text we are working so hard to reduce.
I realized a few years ago that one of the most important aspects of writing software, to me, is to build it for people. For several years, I thought, given enough research, there was a technical solution out there that would help me to finally discover a way back to people.
As has been said many times before, there is no technical solution for people problems.
The more I learned about the sociotechnical1 inner workings of teams building software, the more I realized that no amount of technical knowledge would ever replace the value of better understanding people.
Jessica Kerr leans into Nora Bateson’s concept of symmathesy2, “learning together”, as a description of the kind of work software developers do. This word is steeped in the notion of human systems, working together, communication, discovery, and much more. In order to be more effective symmathesistic team, we need tools.
There are numerous tools, and likely near-infinite approaches to developing an effective group working symmathesistically, however, it seemed most reasonable to lean into something I already understood: the metastructure3 of programming languages.
I ended up pulling a thread and landing squarely at the intersection of programming languages, communication, and linguistics. There are a number of reasons why any programming languages, as a core set of syntactic rules, would not be considered a language in isolation. On the other hand, when we consider the way programming languages are used by people, and the novel structures that emerge, it looks less like machine-generated commands, and more like the way people actually communicate.