What is the outer context?
When programming anything (and I mean absolutely anything); one of the greatest things I learned early-on was that context matters. Even simple operations like addition and subtraction are littered with contextual nuance to avoid overflows, underflows, precision errors. The machines are our tools, and they are here to help, but sometimes we need to help them, and ourselves.
If you've programmed hello world, regardless of raw ISA-specific byte-code or drag-and-drop GUI, you'll understand that given a different device, or the wrong editor, your code should be useless. This is one such context, which is important. Not all people understand this, because logically they fail to induct the context that businesses benefit from a fractured compute mindset; or they just feel like a computer is a computer is a computer.
We can do a lot to help these people to understand. Using analogies such as you wouldn't put gas in an electric, or don't put diesel in a petrol, and vice versa.
We can also help ourselves by trying to document our software, and dependencies. Everyone should know this, and many people do. What they miss is generally the context. Lost in a sea of feel-good phrases like YAGNI, or "move fast", "don't be afraid to fail".
Commonly overlooked contexts
- Shared, versus exclusive environments
- Generation of software product
- User setup, including input language
- Supporting code or systems
That is not an exhuasive list, but it's quite often that I see people treating their cloud compute, the same as their laptop. Those things are not the same!
If for example you were to run a program, which used multi-threading to deal with network IO, but then added multiple sub-processes of a multi-threaded decompression or image manipulation program: You're going to have a bad time.
This year I encountered a problem with a calendar tool at work. Calendars are hard and anyone that reports differently is a genius or a fraud.
The error reported by the much maligned JIRA we use to manage our software, was that incorrect availability was showing via our calendar. I started by checking the payload. No context was recorded by the error reporter, so we had time taken retrieving that. Once I had that, I'd be in a position to write a test.
Most bugs were sadly most easily visible from a blackbox take on the system. Confusing fixtures, erroneous comments, a system that looked like the result of some academic study, and a gradually rotting stew of code.
I noticed the result we got had less than 31 days for a 31-day month. Knowing about calendars, and that this was from a backend system; I went to that backend code-base and found some more answers. I noticed 30 was the limit on the number of days returned, so I increased the number of results to 31, and sorted by date.
Some cases resolved. I declared mission success. It wasn't until much later that I found the real problem was that the frontend in one specific place did not page forwards or backwards, and the query used to select dates from a perhaps naive attempt at date-spans meant some events were never captured.
Once I had this context, fixing was easy. It just took a UX designer, me and three frontend specialists to establish the context.
This made me sad. Not because I didn't solve right away, but because with the context available, I could give this to any junior or intern programmer and teach them something. Instead it had tied up many people.
Commonly considered contexts
- variable scope
- library / framework features
- programming language
- team preferences
The above is also not exhaustive, but represents something I encounter people thinking about. It's a very different list to the unconsidered list. Most of these are immediately obvious when troubleshooting or debugging. Oh I called X and it's not available until after Y happens. I want to store files and ActiveStorage is something that works well with Ruby on Rails. I know that if I use this approach, then team-mate will like or dislike.
I feel that both sets are important, and I would not like to represent that I always take full-stock of all context. I'm not a machine, so it would be quite unrealistic for me to believe that. But I do feel like one is easier than the others.
As all good programmers will know, encapsulation helps hide the unnecesarry implementation details. This is absolutely a readability win. Often though, we move on to the next thing, or are standing on the shoulders of giants, long dead or retired, that defined many parts of the systems we use, without adequate, or accessible documentation. Worse still, even with the documentation, we lack context.
so the other kind of interesting thing about x86 is, that like no one really knows exactly how many instructions there are. Like if you get an Intel x86 like manual these days, it's like this big (visual demonstration). Like 5,000 pages, so it's like, really unwieldy to deal with.Jessica Frazelle - A dive into RISC-V - dot Go [Video]
One of the other problems is specialisation. Will your React DEV really understand why webpack is so much slower than webpack-dev-server, or will they simply state that it doesn't save files? This leaves even the experienced guessing. Turns out that because it does a lot in-memory, it seems faster. One alternative to this blind acceptance is to copy sources and build within a tmpfs, if you have enough RAM and the people to do this. A far simpler solution, which I love is to not use WebPack from day zero.
What am I selling?
Honestly, nothing. I just hate putting piles of nonsense in my head next-to useful information. If more people record context, it can shave off time re-constructing context after-the-fact; help drive to better solutions faster.
Some strategies that may help with this
- Really critically think about your dependencies.
- Try to delve a little deeper than the point your framework magically selects your code.
- Read the framework source code.
- Try to explain the context or sequence of events to a less experienced person.
- Contribute to documentation.
- Try to find out how a thing you use, that you didn't write works.
- Try to re-approach some problems without following others.
- Revisit assumptions.
- Try to think outside the terms of the technologies you use.
Ultimately, we got ourselves into this mess, and only by uncovering existing context, perhaps lowering the amount of context needed, will we reach our goals of easily maintained, understandable software.