The Seven Deadly Sins of Software Development

Original author: Yegor Bugayenko
  • Transfer
Translated by Seven Deadly Sins of a Software Project by Yegor Bugayenko .

Maintainability is the most valuable virtue of modern software development. Maintainability can be measured mainly by the time it takes a new developer to delve into a project before it makes significant changes. The more time it takes, the lower the level of maintenance. In some projects, this time is close to infinity, which means these projects are practically unaccompanied. I want to tell you about the seven deadly sins that make a software product unaccompanied.


Anti patterns



Unfortunately, the programming languages ​​we use are too flexible . They allow too much and forbid too little. For example, Java does not forbid you to place the code of the entire application in one class with a couple of hundreds of methods. Technically, the application compiles and starts. But this is a well-known anti-pattern Divine object .

Thus, the anti-pattern- This is a technically feasible way to design an application so that it is obviously wrong. In each programming language, there are a fairly large number of anti-patterns. Their presence in your project is similar to a tumor in a living organism. Once it began to grow and it is already very difficult to stop it. In the end, a living organism dies. In the end, your project becomes unaccompanied and needs to be rewritten.

Once you made a couple of anti-patterns, and their number, like a tumor, will only grow.

This is especially true for object-oriented languages ​​(Java, C ++, Ruby, Python), mainly because they inherited a lot of things from procedural languages ​​(C, Fortran, COBOL). That is why OOP developers tend to think in a procedural and imperative style. Unfortunately.

By the way, in addition to the existing list of well-known anti-patterns , I would like to add these few points from myself , which I consider to be bad development approaches.

My practical advice here is to read and learn. Perhaps these books will help you. Always be skeptical about the quality of your code and do not relax when it "just works." Like cancerthe sooner you diagnose it, the higher the chance of survival.

Untraceable changes



When I look at the history of commits, I should be able to tell about each change: what was changed, who made these changes and why these changes were made. Moreover, the time it takes to answer these three questions must be measured in seconds. Most projects do not. Here are some practical suggestions:

Always use tickets . It doesn’t matter how small the project or team is, even if you are single, create tickets (GitHub Issues) for each problem that you have to solve. Briefly describe the problem in the ticket. Use the ticket system for intermediate thoughts, so that later it would be clear what “those few commits” were.

Link tickets and commits to each other. Of course, every commit should be accompanied by a message. Silent commits are dirty practice, and I won’t even discuss why. But the message alone is not enough. Each message should begin with the ticket number with which you are working. GitHub (I'm sure that you are using it) will automatically link tickets and commits, making it possible to better track changes.

Do not delete anything. Git allows us to do push-force, which overwrites the whole branch that existed on the server before. This is just one example of how you can destroy development history. Often I saw people delete their comments on GitHub discussions, so that their tickets look more “clean”. This is simply wrong. Never delete anything; leave your story, no matter how bad (or ugly) you think it is.

Complex releases



Each piece of software must be packaged before it is delivered to the end user. If it is a Java library, it must be packaged in a * .jar file and released on some repository; If this is a web application, then it must be deployed on some platform, etc. It doesn't matter how big or small the project is, there should always be standard procedures that test (test), package (package), and deploy (deploy).

An ideal solution would be to automate these procedures to such a level that they can be launched with a single line command:
./release.sh

or
mvn deploy


Most projects are far from this. Their release process always involves a bit of magic, where the person responsible for this (also known as DevOp) has to click some buttons here and here, log in somewhere, check some metrics, etc. Such a complex release process is still a typical sin of the entire software development industry.

I can give only one practical advice: Automate this. I use rultor.com for this, but you can use any tools you like. It is important that the whole procedure is fully automated and can be performed using the command line.

Voluntary Static Analysis



Static analysis is what makes our code look better and therefore works better . But this happens only when the whole team forcibly (!) Follows the rules dictated by the static analyzer. I wrote about this in Strict Control of Java Code Quality . I use qulice.com for Java projects and rubocop for Ruby projects, but there are many options for each language.

You can use any analyzer, but make it mandatory! In many projects where static analyzers are involved, developers write beautiful reports and continue to write code as before. Such a “voluntary” approach does not give any benefit to the project. Moreover, it creates the illusion of quality.

I am saying that static code analysis should be an indispensable step in your production pipeline. The assembly should not take place if any static analyzer indicated a violation of the rules.

Unknown test coverage



Simply put, test coverage is the percentage of code that is tested by unit or integration tests. The higher the percentage of coverage, the more code is run during testing. Of course, the greater the percentage of coverage, the better.

However, many developers simply do not know the percentage of test coverage. They do not measure this metric. They may have tests, but no one knows how deeply they penetrate the code and how much of the code is not covered by the tests at all. This situation is much worse than the low percentage of coverage that can be measured.

A high percentage of coverage is not a guarantee of high quality. It is obvious. But an unknown percentage of coverage is a clear sign of maintenance problems. When a new developer joins a project, he should be able to make some changes and see how the tests respond to this. Ideally, the percentage of test coverage should be measured in the same way as in the case of static analysis, the assembly should not pass if the value falls below some predetermined threshold (usually about 80 percent).

Endless development



By “infinite” I mean development without stages (milestones) and releases. It doesn't matter what software you write, you should periodically assign versions and make releases. A project without a clear release history is an unaccompanied mess.

To a greater extent, maintainability is when I can understand you by reading your code.

When I look at the source code and the history of its commits and releases, I should see what the author’s intentions were, what happened to the project a year ago, where he is going now, what is his development plan, etc. All this information should be in source code and, most importantly, in Git history.

Git tags and GitHub release notes are two powerful tools that provide me with all the information. Use them to the fullest. Also, do not forget that each binary version of the product must be available for immediate download. I want to be able to download version 0.1.3 and test it right now, even if the product is now in version 3.4.

Undocumented Interfaces



Each piece of software has its own interface through which it should be used. If this is a Ruby gem, then there should be classes and methods that I want to use as an end user. If this is a web application, then there should be web pages that the end user will see and use. Each software product has interfaces, and they must be carefully documented.

Like all of the above, this also applies to maintainability. As a new programmer on the project, I will immediately begin to study its interfaces. I must understand what he is doing and try to use it on his own.

I am talking here about documentation for users, not for developers. In theory, I am against the documentation inside the software. In this I fully support Agile Manifesto- A working software product is much more important than detailed documentation. But this does not apply to "external" documentation, which is intended for end users, and not for developers.

So, the interaction of end users with your software product should be clearly documented.

If your product is a library, then its end user - the programmer who will use it - do not develop it, but use it as a "black box".

These are the criteria that are used to evaluate open source projects in our award competition .

Also popular now: