3 Development Anti-Patterns Disguised as Best Practices

3 Development Anti-Patterns Disguised as Best Practices


About the author

Albert Row is a senior software engineer from the San Francisco Bay Area with over 13 years of experience as an individual contributor, technical lead, architect, open-source contributor, and manager.

Albert has been a certified reviewer on PullRequest since December 2019.


images/3-development-antipatterns-often-mistaken-for-best-practices.jpg

Always Reusing Code

Reusing code is a best practice, frequently suggested via the DRY acronym. DRY stands for Don’t Repeat Yourself and most of the time this is good advice. Implementations generally should be DRY and code should be reused - most of the time. There are some places, though, where reusing code is either less than optimal or downright dangerous.

Reusing code between test suites and implementation can be dangerous. If code is used to test, well, itself then the resulting test can be useless. Some reuse is OK, such as using ORM model code to set up a specific test, but many other instances are dangerous. Systems with substantial logic should not be leveraged to test themselves, or relied upon to test other parts of the code. Duplication between test code and implementation code is usually intentional and a good practice. The duplication allows the programmer to verify the correctness of the implementation with a greater level of confidence.

Sometimes inside of an implementation a little duplication is easier than slavish devotion to DRY principles. Sometimes reusing a piece of code would trigger a large refactor or make the overall system more brittle. In these situations introducing some duplication to avoid a more dangerous or harder to maintain state in the system is the logical and correct decision.

Never Duplicating Data

3rd normal form is a best practice for database design, but it is not always the most desirable one. When designing a system to conform completely with 3rd normal form, it’s common to encounter situations where certain read paths frequently taken by the application will require multiple joins to load all of the required data for the application. In these cases, it may be that design in 3rd normal form leads to inferior performance in the application. Denormalizing, then, can be the right solution - duplicating some data across multiple tables to speed up the read path and moving some of the complexity to write.

Duplicating data is highly desirable in distributed consensus designs and to make other data systems more resilient - replication is a valid and frequently used strategy. In Data Warehouses and Data Lakes, it’s common to find the same information duplicated many times in order to support multiple different types of analytics performantly - duplicating data can actually reduce costs, particularly for systems where the user pays for compute and storage separately. With the decreasing cost of data storage these approaches have moved from the exception to the norm for good reason. Optimizing for reduced storage costs is less of a major concern for most organizations.

Prematurely Building for Scale

Scalability is not usually the biggest concern at any organization, especially when creating a new product from scratch. While architecting software to handle scale well is a good thing the additional effort only bears fruit if there actually is scale that needs to be handled. Building for scale when scale is not likely to appear usually results in extra expense for the company and a system that is harder to change down the line. Extra expense can take the form of an application that takes longer to build, is more expensive to host, or both.

What should be considered as well in the cost of prematurely building for scale is opportunity cost - what would the organization have learned if the system had been built more simply and shipped sooner? What other systems could have been created in that extra time, and what value could they have provided to the company? Sinking Engineering cycles into handling scale prematurely has non-trivial business impacts that can affect the success of an organization.

TL;DR

Software development practices need to be tailored to suit the problem at hand. No hard-and-fast rule can ever be correct in all circumstances, and slavish devotion to any particular Engineering ideal can lead a practitioner into grave error if not tempered with an understanding of the needs of the system and the wider organization. Most anti-patterns masquerade as best practices, and look similar to the one they’re imitating. They’re just twisted in a critical way that makes the application of the ideal harmful.

Always hold on to common sense when making engineering decisions, and ask for feedback from across the team to help find a way forward that works well for everyone.


Also be sure to check out:


About PullRequest

HackerOne PullRequest is a platform for code review, built for teams of all sizes. We have a network of expert engineers enhanced by AI, to help you ship secure code, faster.

Learn more about PullRequest

Albert Row headshot
by Albert Row

May 18, 2021