Sunday, December 27, 2020

Bugs and Weaknesses

 When code goes wrong, there is a wide range of different outcomes.

Some code is obviously wrong. It does something unexpected and so bad that the objective of using the code for its intended purpose is completely derailed. This is generally what most people mean by a ‘bug’. It’s followed by a need to change the code swiftly and get that back into the operational environment, so as to unblock the user.

Some code is annoying. Technically it works, it is usable, but it just makes getting something accomplished slow or painful. I tend to refer to this as a bug as well, in that the behavior actually bugs someone. These types of issues are often not fixed, and there is little urgency anymore in correcting them. Most people focus on adding net new features, not correcting historically rushed work.

The other category of wrong code is a weakness. This is code that appears to work, and most of the time works fine. It’s just that under limited scenarios, or even at some point in the future, the code no longer does what is expected. Weaknesses manifest themselves, cause problems, but subsequent investigations are often not deep enough to find them. So, they can be infrequently repeating problems that burn through time, where nobody is positioned to find and correct them. The other scenario is that seemingly unrelated changes to underlying dependencies suddenly cause the behavior of the code to majorly change. Some small change that should not have been a problem, becomes one. Weaknesses are the most pernicious of all coding errors because you can be looking straight at them and still not notice that the code is wrong. 

Weaknesses are far more common now, primarily because the underlying technologies and environments have gotten way more complicated. This helps disconnect the authors of the code from the full weight of its behavior. As programmers use more code and understand it less, weaknesses become more common. The code works sometimes, but sometimes it doesn’t. 

Really, these should be classified as bugs, but if we did that since there is a lot of very weak code out there, we’d have to admit that very little of what we build actually works correctly. That’s the opposite of our industry trends right now where we over-emphasize that we’re super flexible and can throw together stuff fast enough to match the users constantly changing their minds. It’s this real-time reactivity that people seem to want; they’d rather have a lot of bugs than have to wait a while for stuff that lasts. 

Tuesday, December 15, 2020


There are a bunch of fairly simple ideas that would make large-scale software development easier and less volatile.

The first one is ‘pre-fab’ systems. 

The idea is that you get a fully set up, architected system, ready to go on day one, right out of the box. It doesn’t do anything, you still have to add in screens and the core business logic, but everything else is there: users, security, configurations, database, domain tables, etc. 

Each one is for a specific tech stack, there are no configurable options, all that work is done in advance. It’s all set up, all of the decisions have already been made. 

There would be documentation and comments that tell you where to add in your code to alter the mechanics. It’s understood that it is all ‘untouchable’ and will need to be upgraded to newer versions as time progresses so that the ‘porting’ process is built-in already. 

The primary reason this is super helpful is that we see a lot of early programmers essentially ‘cheat’ on the setup of their projects, and those deficiencies propagate into everything else. 

It’s not easy to understand how these systems need to be set up, built, deployed, upgraded, etc. Most projects don’t need some special type of clever custom solution, they just need the boring, correct, dull setup that ensures that future work will fit nicely and be able to move forward.

A ‘standards’ and ‘modeling’ reference web site. 

Not one that is for-profit, or where these are fees to join, but rather an open international standard site that is funded well enough that it can focus on its key objectives, not making or raising money. 

The objective is to make sure that people can easily use the appropriate standards and data models in their systems to make them work correctly. It’s not uncommon in coding to find people who have manufactured their own bad standards, like ISO Country Codes, to disastrous effects. 

There is no one resource to point people to search, and say if the standard is here, you ‘have’ to use it. So, instead, we get countless bad reinventions of the same stuff, over and over again, with a large variety of naive errors. 

After decades, there are a huge number of ‘great’ standards, and most industries have a standard way of modeling their own entities. So, if we capture that, and provide a strong reference site to lookup stuff, and reuse it, a lot of the weirder code out there will gradually disappear. 

In most systems, less than 10% of the code is special, the rest is rather boring and it should be rather boring, which is a good thing. Put your creative energies into the parts that matter, then just put up the rest of the stuff that is needed around as, as cleanly as possible.

A software development ‘building code’. 

A little book of non-controversial, unbreakable rules that are just not up for discussion. They’re not popular, they are timeless. A kind of best practices on steroids, except that you can’t argue with them. 

There are some rather obvious candidates, like don’t ‘misnamed’ stuff, ‘handle all of the errors’, and you always need development, testing, and production environments. 

They are timeless and absolutely identical for each and every tech stack, each and every project, but they seem to keep getting forgotten, rediscovered, and then forgotten again by each new generation of programmers. 

Getting this into a little, non-controversial book of simple rules that ‘must’ be followed would literally save probably billions of hours of people arguing over their validity.

It’s not just discussions between programmers that get affected by this, it is also the influence of strong stakeholders that contributes to people doing obvious things that they shouldn’t. 

A trustworthy, dynamic schema, persistent solution, that preserves deterministic properties like ACID. 

That is, the quality of a program is predicated on its ability to ‘remember stuff’. If it forgets or gets confused, then it is not a particularly useful program. 

Having to establish, in advance, a strong locked-in schema (that should be 3rd or 4th NL) is a problem both for people learning about the technology, but also because it anchors any and all of the following code. If it anchored it to the wrong spot, that is usually ‘slowly’ fatal to the entire endeavor. 

So, instead, we build something that persists but is also easily changeable within the system architecture. So, the system can save an entity, then later upgrade the attributes of that entity safely, to allow both variations to be accessible in the system (and an easy path to move an older variation forward). There are tools to track the differences and to safely clean up when possible. There is an assumption that the sum of the data is spread over many instances of it running.

If schema changes are trivial and easily codable, then the fear of making them in a big system will diminish and the focus can return to extending the work, not just trying to work around it.

In finality

All of these ideas are centered around keeping programmers from doing the ‘wrong’ work. In most cases, their job is to extend systems with new features that make life easier for users, but if we dig into a lot of wayward development projects we tend to find that the work and focus ended up in the wrong place. That in turn caused political issues and the whole thing went downhill from there. 

There are always interesting puzzles to solve and areas in development that need creativity in all projects, but that effort needs to get applied to the right areas, not just wantonly all over the place. Some parts of building systems are dull and boring, and that is a good thing, as it should be. In the end, it is just work that needs to get done well, in order to get enough baseline quality into the system, that the project can keep making progress. If we are continually ‘scrambling’ that work out of some strange desire to leave a ‘legacy’ or prove ourselves, then maybe we should find a way to prevent that as an ongoing problem.

Sunday, December 6, 2020


I was kind of a mess when I first started programming. My code was awful, poorly thought out, and extremely messy. My thinking was murky and I had no sense of organization. I’d just madly flail at coding with a lot of energy and enthusiasm, unfortunately, the results weren’t particularly useful.

That changed as I worked with really skilled people who had good habits. When you are struggling at doing something simple, and you see someone breeze through work that is way more complicated, you know that some of that is experience and knowledge, but there are other attributes as well. As I watched them work, I started to see the habits that kept them in check, that kept them from going astray.

It’s worth noting that for every habit, that there are always times, partially in crunch mode, where you have to not follow the habit, and do something worse. That is fine, as the point of a habit is that it is the default when you don’t have a reason to choose some other behavior. It’s where you start, and then from a little consideration, you may choose to do something else, but if there aren’t extremely good reasons for taking a shortcut, you should definitely fall back to habit.

Cleanup, Cleanup, Cleanup

It’s not just the code. Working in a messy office, or with a messy environment, where absolutely everything a mess, is draining. You keep stumbling over things, it just slows you down. Keeping things nice and tidy takes time, but it is always less time than getting bogged down by a mess. It’s a really good habit to stop every once in a while, and clean a bunch of small things up. Clean up your office, your desk, the file system, your machine, the documentation. Whatever it is, it all needs to be kept tidy. There is no other habit, that is so obvious, that seems to influence the productivity of programmers. Those that whack out a lot of code and leave a lot of mess at the same time, tend to get overwhelmed by their own inefficiencies they created. Those that clean up as they go, tend to get faster and more efficient as time goes on.

Write it down

In an environment, where there are millions of things flying around, it is easy to forget stuff. It is hard to work with people that constantly forget stuff, you can never trust them to get their part of the problem solved, you have to constantly remind them. The best programmers have memories like elephants, but really they don’t. They just spend the time to keep lists of things that they need to know, and things that they need to do. If you develop the habit of writing stuff down, then it isn’t that much of a leap into writing it down in a way that you can share it, and sharing it in a way that everyone can find it. This set of habits makes sure that people trust you to get your work done, even when it is a crazy environment and everything is constantly in flux.

Fix it Now

Procrastination is the enemy of getting something big to work. If you keep ignoring little issues you see coming up, and instead focusing on getting something bigger down the road, a lot of the time you will come to discover that the big issue is not what you thought it was because of the little ones. That is, if you pass over 5 minor issues to fix a bug, it’s not unlikely that one of those minor issues is part of the bug, or influences it, or even convinces you to not look at the bug anymore. But it’s not just bug fixing. It’s all of the code, the documentation, the analysis. Basically everything. If you can, fix it now. Fix it right away before moving on, even if you think it is just slowing you down (it isn’t). 

Don’t use it Without Understanding it First

The temptation is to cut and paste some code from somewhere else, thinking that someone else understood enough of it to be usable. That’s a pretty ‘strong’ assumption; often when people throw together answers on the web, they kinda get it, but not fully. Their example isn’t meant to be used verbatim, but rather as a means for guiding you in your search for stronger answers. That is, if their example has 4 lines of code, you have to go through each and every line and figure out how it works first, before using it. If you skip that step, you may have completed the ‘task’, but you cheated by not understanding it fully. Later that will haunt you. So, an example on StackOverflow isn’t the final code, but rather the parts of the code that you should now go investigate further.

Take the Long Way Home

In a rush, you may have no option but to take short-cuts, but they are usually weak, with consequences that are not immediately obvious. When you are not in a rush, it is very important to force yourself to take the long route. The long, slow, ‘correct’ way of doing things. You have plenty of time, you have to switch out of crunch mode and back into ‘do it right’ mode. Doing it right may be more boring, it may be more tiring, there may be more work, and it may be harder, but unless and until you know how to do it right, doing it wrong is going to mislead you into false assumptions. Really you have to do it right at least once, or you’ll never understand the full context or the consequences you are missing. It is better to do it right a lot, then it will become muscle memory. It’s a habit that will save a lot of pain later. 

Leverage it

Whether it’s knowledge, tools, paradigms, or idioms, it is better to work with what you know and understand that first, before trying something else. That is, if you have one tool that does 5 things pretty well, it’s a better choice than having 5 tools that each do a single thing really well. More tools, in itself, is more complexity and having to use a different tool for every task is a lot more cognitively demanding, and more likely to go wrong. If you pick a tool, then you should spend the time to figure out ‘everything’ it can do, and use it for ‘all’ of those things. That’s the same for every other aspect of the work. Leverage what you’ve got, before heading out to find something new. Even if that new thing is slightly better, that’s not enough to justify adding it into the mix. If the things you have cannot accomplish what you need, or are extremely poor at it, then you have to add something new to the mix, but that should be the extreme case, not the default one. This isn’t a directive against learning, since one always needs to learn a lot of new things, but rather a point that learning something deeply is more useful than learning a lot of stuff at the shallow level. To get things done well, you need enough depth to understand them and make them work as expected.

Keep an Open Mind

There are always a lot of popular trends out there that are basically silver bullets. They claim that if you do something in a certain way, all of your problems will magically disappear. That’s fine (and this post is no better), but it is not a good idea to take these ideas as articles of faith. They might be right, they might be wrong, or they might be right sometimes and wrong for others. If you buy into them, completely, then you’ve closed your mind to learning and growing, which is not going to end well. There are plenty of conventions, idioms, styles, etc. that work well enough in the limited circumstances, but are really bad ideas outside of that range. It’s okay to try something and see if it really does fix or improve the problems, but it’s equally important to be objective about its success and to bail on it, if the side-effects are worse than the original problem.

All The Little Things

We’re told not to spend too much thought on the little things. They are ‘little’ after all. But in software development, when the millions of things we have to work on are all predicated on little things, it turns out that spending time thinking about them is vital. So, it’s another great habit to not just wave your hand and dismiss something as being ‘little’, but instead to spend at least a few minutes giving it consideration. Oddly, once you are in this habit, and you’ve considered lots of little things, it all a) gets easier b) gets faster and c) the quality of your work improves. Little things matter.

It’s Okay to be Pedantic

Unfortunately, computers are rigorous and strict environments. They are a ‘formal’ system, so they are 100% pedantic. A little one-character mistake can bring down the entire system. It’s just the way that they are. Lots of programmers try to rebel against this, and they love to say ‘it doesn’t matter’, but the really great programmers know that it does matter. The tiniest of things, every little bit, and byte. All of it. It matters, it’s worth thinking about and it is often worth discussing. There is nothing wrong with being pedantic, and at times in the development process, it is a necessity, not a defect. The quality of a system is the quality of the thinking and organization that went into the construction of that system. 

Expect it to Go Wrong

If you write some code, it will have bugs. If you spend a lot of time, you can find and remove most of those bugs. It takes a long time, but you could actually make it work nearly correctly. However, you probably don’t have anything close to the amount of time necessary to do that type of work properly. As such, when you put any code into a production environment, bad things ‘will’ happen. You should expect this, and anticipate it. The best you can do is correctly guess which ones of those bad things will be the most embarrassing, and do some extra work there to mitigate their appearance. But you’re never going to have enough time to catch them all early, so you also need to have strategies like being able to roll back everything to an earlier version. Rollback, fall back, turn off, etc. Protecting yourself in this way isn’t a waste of time, it’s just the necessary insurance to deal with those expected epic failures, that will always occur.