Back to all articles

The art of cutting corners

Artem Rudenko

Artem Rudenko

Software engineer, founder of ottofeller.com

Anyone can build perfect software if given infinite time and resources. Some can build quickly, but far from perfect. A few can build sufficiently good things on time.

Knowing when to cut corners is an essential skill for delivering quality software on time. Each time you cut a corner, you are making a tradeoff. You implement a suboptimal solution to the problem at hand, but you save time.

Walk the middle path

We learned that it takes experience and insight to know which tradeoffs are a net positive for the project and which are a net negative. If you prioritize only short-term development velocity and cut too many corners, you end up with a big ball of mud which is expensive to maintain and may be so low in quality. On the other hand, if you make zero tradeoffs and always strive to implement the optimal design for each part of the system, you're unlikely to deliver a functional product on time — if at all.

To build software that is both functional and on time, you must walk the middle path by cutting some corners. Knowing which corners are okay to cut is what separates successful teams from unsuccessful ones.

Set priorities

Just cutting corners blindly does not really work. We found that one way that is efficient is to create a list of metrics by which the quality will be judged, and then order the list from most to least important. The types of metrics are often different from project to project. For some projects, general things would serve as metrics. E.g. usability, maintainability, visual design. Wjile other projects treat functional features as distinct metrics.

The trick here is to be very careful while deciding on priorities and defining the list of important things. And then, when the list is all set, just strictly follow it as a no brainer.

Don't think twice before deciding if a hardly going feature is worth excluding from a release — simply check with priorities that were set before.

Accumulate technical debt

On practice cutting a corner usually means implementation of a quick & dirty solution now (or ignoring it at all) and flagging it for later refactoring. That's how you accumulate your tech debt.

It's very important for team's morale to make it clear that presence of tech debt doesn't mean that problems are not being ignored, but rather being delayed so that development effort can be focused on problems with larger business significance.

Once you have acquired technical debt, It is critical to document, categorize and prioritize the debt so that it can be repaid in the future.

Pay back the debt

Adding technical debt to the product backlog is pointless if those backlog items are never reviewed. It's best to review technical debt on a regular basis, such as every sprint or every other sprint.

One technique which we find helpful for staying on top of technical debt is to create a calendar of recurring tasks.

Every two months, we review the primary services of an application and assess what can be improved, and if our initial design is still working well. Another scheduled event on our calendar is, every three months, we review the project's monitoring infrastructure. It can be easy to forget to perform these less frequent recurring tasks, but keeping a maintenance calendar makes it simple to stay on top of them.

Our maintenance calendar is not only for tracking work to be done — it is also used to schedule a review of what we've done so far. During this review, we often discover ways to improve that code that will not require much dev time. Sometimes, our review uncovers critical issues. Either way, the review process helps populate the backlog with technical debt.

Closing thoughts

In our opinion, knowing which corners to cut, and how to maintain a balance between speed and quality is an essential skill for software engineers. Most of us need years to develop it. Some of us consciously refuse to cut corners and prioritize perfect code over all else. But a pristine codebase with an ideal architecture is ultimately worthless if in the end the software does not deliver value to the business.


Other articles

Streaming real-time data into Snowflake using Kinesis Streams

Significant growth of a product’s user base always leads to challenges for data engineering teams. The volume of events produced by millions (or billions) of users makes it almost impossible to use standard solutions for ingestion as is. It’s always nuanced and adjusted for particular situation.

Gradual rollouts with AWS Lambda

Learn how to mitigate deployment risks using AWS Lambda's gradual rollout feature, enabling safer, incremental updates to your product's backend.