When solving problems it is inevitable that a proposed solution will not meet the necessary requirements. When groups communicate it is inevitable that a miscommunication will occur. When you recall information it is inevitable that you will misremember. Being wrong is not a niche occurrence and should not be treated as one. Rather, being wrong effectively is a skill worth learning, allowing for faster course correction and a more helpful, productive work environment.

An incorrect answer is an opportunity for a correct one, but all involved parties must be prepared to confront an answer's potential incorrectness. Initially, this is the most difficult part of the process. Once understood that exploring more correct answers and accepting previous ones may have been incorrect, a more important question can be regularly posed: Am I wrong? Consider that you may be and the knowledge that can be gained from understanding when you are.

Be ready to be wrong.

Building something new brings with it a burst of motivation and inspiration. As the project gets closer to the end goal and becomes “good enough” that motivation reduces proportionally. However, this “good enough” benchmark is rarely accurate. Instead, it's often a misinterpretation: good enough for you, the creator. When you begin to feel this reduction in motivation, inspiration, and momentum, it is time to collect feedback on what you've done so far. Once in the hands of users the cut corners, missing functionality, lack of documentation, and other flaws surface. These are the things that make your project truly “good enough.”

Python is a powerful language. So is Java, C#, PHP, JavaScript, etc. You can pick just about any one and it'll get the job done today. However, few of them will hold up over time.

The thing that I've come to learn in my years of programming is that it's important to value readability and maintainability. Perhaps even more-so than immediate development. Software lives for a long time. Far longer than you'd ever expect, or sometimes even want, it to. Because of this, I tend to not recommend Python, Java, C#, PHP, etc. The ability to read and understand code is paramount. Java and C# introduce far too much syntax bloat to make things easily digestible for newer developers. Reading code then necessitates a proper way of documenting code. Python strings are out. Maintenance is difficult and/or nigh impossible in dynamically typed languages. As much as I love JavaScript, I wouldn't write a new project with it for this reason. Without type annotations, it's very difficult to come back to a project after several months or years and make a change without unknowingly breaking something else. It's also harder for a newer developer to contribute to a project without accidentally breaking something.

When considering a language for a project, ask yourself: Will it last?

Software grows, adding new features and paradigms along the way. If you're not careful, it becomes less opinionated about how or what is done. One small feature to support dynamic configuration begets a system of loading various file types and executing arbitrary code. Where there could have been one clear way to support this feature, there are now several confusing ones. Instead of having fewer opinions for more use cases, software should be more opinionated to focus on its core use cases.

Opinions imply constraints on our projects. They limit what we can do with the tools we are given. However, they also reduce the work we need to do, letting the tooling pick up the slack. Strong opinions allow software to be more focused and built more quickly. Accounting for fewer things also allows programs to be simpler. In turn, opinionated tools allow us to develop more focused, smaller, more opinionated applications. Rather than extending to every use case, it's important to maintain the core focus of your project; it's important to be opinionated.

Applications and tooling continue to follow the same cycle: start small, inflate with features, and finally become so unwieldy or unusable that users flock to the next application that promises to be smaller and more focused. This cycle is not sustainable for creators, due to the ever-growing cost of new features and increased maintenance, as well as users, due to the constant fear that they will have to pack up and move to another service. As users, we can Mind What We Can Manage. As creators, however, we have the ability to solve this problem. How, then, do we avoid this cycle? How can we keep our software small, focused, and responsible only for the problems it was built to solve?

We Stop.

The ability to know when a product is finished is not only a crucial skill, but one that our industry severely lacks. Doing so saves time, money, and headaches for everyone involved. Instead of continuing to stuff features into a given product, it's important to stop and ask “Does this solve the problem this product was built to solve?” Each and every application or tool is created in an attempt to solve a problem. At some point, that problem is solved and no longer requires additional changes. If you ask yourself this question and your answer is an emphatic “Yes”, then that feature may well be a core part of your application or tool that was previously absent. However, any other answer is a great time to step back and try to understand why it doesn't. It's likely a great sign that you should seriously consider stopping.

Not every idea is great. Few will last for more than a moment. For this reason I don't write them down, save for a few exceptional circumstances. Instead, I wait. Good thoughts tend to stick around and great thoughts tend to be all-consuming.

Rather than saving every idea as it arrives, my strategy has been to let these thoughts free, expecting the best ones to return. Often I'll expect this “boomerang effect” to happen more than once, enabling me to better gauge the quality of a given idea and the motivation I have to pursue it. This strategy has also given me more time and freedom to construct those thoughts as I find putting ink to paper has a sort of finality to it that codifies this thought, disincentivizing further change.

From this strategy, I've produced:

And many more.

“Perfect is the enemy of good” is a surprisingly dangerous thing to say. Unprepared, it could cloud your judgement, encouraging you to produce something that isn't even good simply out of the fear of making something perfect. It's important to be prepared as this adage is bound to appear throughout the creative process. Constraints may force us to compromise or remove features outright, but the standards we have for the parts we do keep should not sway. As well, the parts we both add and remove should be scrutinized. Sometimes things need more time, other times we need to Know When To Stop.

What happens when a fundamental piece of your program no longer exists? When a service you rely on is discontinued? These are problems we've only seen increase with the high amount of churn in the software world. Rather than relying blindly (or hopefully) on an external service or project, we should be diligent in our search and assessment to determine the reasonable safety of our choices.

Assessing software before committing to a given project can be difficult. Some people rely on “popularity” or usage by a notable company as positive signals to determine the safety of their choice. However, these points of data can be, and are often, completely irrelevant to your ability to keep using a given piece of software for years to come. Instead, I've found, the most important factors are size, code quality, and language. Small projects, written well, in a language you specialize in are perfect candidates. Your ability to step in and (minimally) maintain the project is paramount, lest you be left out in the cold. With this in mind, before binding yourself to an external service or project, ask yourself: “Can I manage this?”

People say “Don't reinvent the wheel” a lot. But what about building a better wheel altogether? I mean, could you imagine if we stopped with wheel v1? It's quite rare that anyone gets things right on the first try. And, even then, in the world of tooling it's just as rare that your needs will align perfectly with a preexisting solution. Every person, team, and business will have its own special set of needs. Sometimes those needs line up well enough with what is available on the market. Sometimes they won't. So, instead of settling for second-best, what do we do? Build a better wheel. You already know what you like, what works, and what's missing. Instead of having to reinvent everything, you only need to come up with a v2.

Make things that already exist and make them better. Don't let others tell you that the status quo is good enough.

I've seen this mentioned quite a bit over the last year: “Don't use Kubernetes for your blog”; “Don't use Kubernetes for just one service”; “Don't use Kubernetes for _______, you don't need it”. Sure, you don't need a lot of things.

I've chosen to run my applications on Kubernetes and, if you were turned off by the naysayers, you might consider doing so as well. Here are a few reasons for why I've decided to introduce this extra complexity:

A learning opportunity, expanding domain knowledge Experimentation Rapidly develop and deploy new applications Ownership and control over the whole system

The most important reason when making this decision for myself was “I want to learn this.” I spent the time learning how to create a Kubernetes cluster, deploy a blog, configure GitOps, etc. Because of that I built the skills to create some really useful infrastructure at my day job.

So yeah, you should host your blog on Kubernetes, you'll probably learn a lot.

Oh, and it also helps that Kubernetes is pretty fun to play around with.