How Much (Knowledge) is Enough to Ship
The problem
What is the problem? This is not always restricted to software engineers, and so this might also sound familiar to those of you in other occupation. Take the following scenario: You have an extremely important client (maybe the first one) that decided to sign up with you (your app or business contract in general). You want everything to be perfect. Or, as an engineer, you are assigned a brand-new project. The only things you get are some high-level requirements, and the main goal of the application. In both scenarios here’s what you want at the point of delivery: No bugs, no errors, top-notch security, high performance, slick UI (in the case of an app). That is the dream. And this is the problem, the dream!
Why is this a problem? Don’t get me wrong, I’m an advocate of the saying, if you can’t dream it, you can’t achieve it. However, I’ve added that in the introduction just so I can burst the bubble from the get go. Striving too aggressively for perfection, usually comes with madness. More often than not, it brings unnecessary stress and creates an uncomfortable work environment. Perfection is to be sought after, but at a cost. You cannot learn everything about the frameworks and tools you use, be them .NET, jQuery, Laravel, you name it. You will never know everything about authentication and authorization. At least not from the point of starting out.
Am I in this situation?
Enough with the negativity. After all, we’re in the business of providing value through software. So, how do you know if you’re experiencing this problem? Ask yourself: Do I spend hours on end trying to find out every single possible detail about a config builder? Am I browsing for hours for answers to questions I don’t need an answer for (yet)? In other words, am I trying to solve problems I don’t even have? Am I thinking in terms of future proofing or MVP?
If the answer to any of the above is positive, then you’re more likely in this situation. This is called paralysis by analysis. And it is not unusual for us to overanalyze a subject until there is a mental block and any more answers identified are just futile. But there’s hope!
How to solve it?
In plain language, you don’t, you learn to live with it. In this case, your app must meet certain criteria to be shippable. It must be performant, otherwise users will stop using it (or can cause issues down the line). It must have top-notch security. Otherwise, your business could infringe all sorts of regulations, that can result in fines and bankruptcy. They all need to be done, but not by learning everything about every component at hand. This would take too much time, and like mentioned, it’s impossible. They can be achieved by following 3 easy steps. In a nutshell, you just start and ship. Take preventive measures and reflect on your situation consistently. Here’s how:
1. Just Start – Convention over configuration
Just start! It’s OK to go back to docs once you’ve already shipped the first version of your app. It is actually healthier to think in terms of Minimum Viable Product rather than trying to make everything future proof, or perfect. This is because the sooner it gets in the hands of users, the quicker you’ll identify the real issues that must be tackled.
Realize you’ll never know everything. There will always be new versions of the framework/tool you use. This does not mean don’t keep up to date to the release notes of your most used framework. Quite the opposite. But try to solve specific problems in a proactive fashion. For example, if your problem is authentication in .NET, research that specific topic, find a good example and go with it. Does it satisfy the needs of clients/project manager/product owner? If so, trust the third-party integrations and move on.
2. Take preventive measures – Test!
Prevent problems before they happen. Probably the best piece of advice in life is this: “A drop of prevention is equivalent to a gallon of treatment”. Most of the times we tend to brush over the most straight-forward practices such as clean, readable code or testing. Have you considered the following? Unit Tests, Integration Tests, Acceptance Tests, UI/UX Tests, Smoke Tests? If not, why? Possibly now is the time to reflect on this matter. Tests can identify issues when the cost of fix is minimal to almost non-existent. Think of it this way: A column from the dbo.Rooms table is removed. Surely you don’t need that, it was just a flag. Running the UT would show you exactly if it was truly needed or not. However, if that UT was not set up in the first place, and that flag was used in a report, that small commit would cause a lot of headaches for your user’s meetings (and ultimately for you).
Database backups (before every single release on any environment). Surely, there is an argument that there is so much cloud space you can use, considering the budged assigned to it. However, one thing to note is it will always cost less to prevent an error than to repair it. Thus, it is always a good measure to take a backup before every release on every environment. However, if budged is tight, make sure the live/production environment has one set up. Why not deleting them from the server after a few months? Just like that, your data is covered for any loss, and your server storage is kept under control.
Code reviews. This is a no brainer as code reviews ensure the system remains readable and maintainable. Do not fall under the trap that unit tests can fulfill the need for code reviews. Not only that, but according to this Quora thread, it is also beneficial for new employees to go through the review process. Maybe have a checklist in place. This could help guide the review process where the scenarios are necessary. It is fairly easy to set a code reviewer policy in place, before the PR can be completed. Here is a guide for how to do this exact step on GitHub.
3. Reflect – Take a step back
Take a step back and ask yourself: Do I really need to learn this (configuration, custom settings, builders) NOW? Is it literally stopping you from the development process? Like the name implies, this is a reflection upon what you have to do and how to minimize your level of stress and upfront effort. While new projects offer the possibility of a fresh start, try not to go down with the idea that everything must be perfect. It is actually common for a new component/framework to reach production without any of the devs knowing 100% how it works. If you take the preventive measures from the previous point, you are covered. Incremental changes to the app will allow for improvements. They will also provide enough time for diving deeper into the subjects you eventually wish to tackle.
The “Do it > Get Stuck > Research > Solve” cycle. We as developers tend to follow this cycle fairly often. This can help wipe out some of the pressure of a new project/feature. Learn just enough about a component to get you started and know about potential security concerns. Wait until you get stuck, meaning a bug comes up, or a colleague identifies an issue (again, prevention is key, this should not yield a data breach or any major error like that). When you get stuck, then and even then, look up the issue. It is likely other people encountered it. If that is the case, apply a similar solution to theirs, tailored for your needs. Bottom line is: Don’t solve a problem that you haven’t already got.
The .NET framework specifically has come a long way. In most cases, defaults are just what you need to ship that app. These days you can find up to date or brand-new courses on Pluralsight or Udemy which I am an avid fan of. A good course will provide the necessary project configuration and set up required for a secure production app. In addition, the course teacher will also brush over any potential concerns. Note them down or add comments in your code for future references. In most cases, default configurations are enough to get you started.
Summary
To wrap up, if you ever find yourself in a situation where you are assigned a new project/feature, or even build one for your own business, try not to try learning everything from the get go:
1. Convention over configuration: Just ship your app, it will not be perfect, but it will never be. You can only enhance it once your users got their hands on it.
2. Take preventive measures – Test: Unit Tests, Integration Tests, Acceptance Tests, UI/UX Tests, Smoke Tests. Make sure you make a habit of adding as many of these in as possible after each enhancement.
3. Reflect: ask yourself, what are you trying to do? How much learning is just enough to ship that app? Think about the “Do it > Get Stuck > Research > Solve” cycle.
I hope this has been valuable to you. Till next week, have a good one! 👋