A set of coding standards

A set of coding standards

We have decided to focus on improving coding practices within my team, and I wanted to provide a digestible summary of key practices. It can be used to guide coding and code reviews, and also as input to an LLM generating code.

I thought I'd share it with you in case you find it useful or a good starting point. This is for Java, but I believe it can be easily tweaked for other languages.

And please I don't want to start a big debate about things like SOLID or clean code. Take what you want, leave the rest.

SOLID principles

  • Single Responsibility - a component (class, method, subsystem, service) should have a single responsibility - one reason to change, one set of clients, supporting a single overall goal. Do?not create open-ended Helper/Util classes.
  • Open-Closed - to add functionality to a component, you can extend it rather than change it. Plug in a new class or a new method. Watch out for large if/then/else statements or case statements. If you have to keep adding code to an existing method, class or service for each new enhancement, you are not following this principle.
  • Liskov Substitution - Every implementation interface should be fully transparently replaceable with another. A caller shouldn't have to check to see what concrete implementation they are working with.
  • Interface Segregation - Keep an interface, which is a contract, as small and focused as possible. Don't try to be all things to all clients. You can have different interfaces for different clients.
  • Dependency Inversion - Dependencies are handed to me, rather than me creating them. This means?do not use static methods, including singletons.

Clean code

  • Let the code do the talking - Use small, well-named, single-responsibility methods, classes and fields so your code is readable and self-documenting. This includes extracting a long set of conditions in an if statement into its own method, just to explain your intent.
  • Principle of least surprise - Make things obvious. Don't change state in a getter or have some surprising side effect in a method call.

Design principles

  • Loose coupling - use design patterns and SOLID principles to minimize hard-coded dependencies.?
  • Information hiding - hide complexity and details behind interfaces. Avoid exposing your internal mechanisms and artifacts through your interface. Deliver delicious food and hide the mess in the kitchen.
  • Deep modules - A good module has a simple interface that hides a lot of complexity. This increases information hiding and reduces coupling.
  • Composition over inheritance - inheritance introduces hard coupling. Use composition and dependency inversion.

Build maintainable software

From https://learning.oreilly.com/library/view/building-maintainable-software/9781491955987/

  • Write short methods - Limit the length of methods to 15 lines of code
  • Write simple methods - Limit the number of branch points per method to 4 (complexity of 5).
  • Write code once - "Number one in the stink parade is duplicated code" - Kent Beck and Martin Fowler, Bad Smells in Code. Be ruthless about eliminating code duplication. This includes boilerplate code where only one or two things vary from instance to instance of the code block. Design patterns and small focused methods and classes almost always help you remove this kind of duplication.?
  • Keep method interfaces small - Limit the number of parameters per method to at most 4. Do this by extracting parameters into objects.?This improves maintainability because keeping the number of parameters low makes units easier to understand and reuse.

Exception handling

This is such an important section, as poorly handled exceptions can make production issues incredibly difficult to debug, causing more stress and business impact.

  • Don't swallow exceptions. Only catch an exception if you can?fully handle it or if you are going to re-throw so you can provide more context
  • Include the exception cause. When you catch an exception and throw a new one,?always include the original exception as a cause
  • Don't return a default value on an exception. Do?NOT?catch an exception, log it, and then just return null or some default value unless you are?absolutely positively sure that you are not hiding a real issue by doing so. Leaving a system in a bad state or not exposing issues can be a very serious problem.
  • Don't log a re-thrown exception. If you catch an exception and throw a new one, do not log the exception. This just adds noise to the logs
  • Prefer unchecked exceptions. Create new checked exceptions only if you believe the caller could handle and recover from the exception

Thread safety

  • Avoid shared state. Keep things within the scope of the current thread. Global classes, singletons with mutable state should be avoided at all costs. Keep classes small, simple and immutable.
  • Know what you are doing. If you must use shared state, you need to be very very thorough that you are both maintaining thread safety and not causing performance issues. Have any code with shared state reviewed by a senior engineer. Also have it reviewed by an LLM; they are very good at catching issues and offering alternatives.

Input validation

  • Public methods need all their inputs validated. A public method could be called by anyone. Protect your code by ensuring all inputs are as you expect them to be.

Testing

  • Test the contract, not the internals. Your tests should support refactoring with confidence. If your tests have to be rewritten every time you refactor the internals, your tests are too tightly coupled to the internals. Avoid using Mockito.verify. Don't expose internal methods or data structures just so you can test them.?
  • Test in isolation. When you test a component, isolate it from its dependencies using mocks and fakes
  • Write clean tests. Apply the same coding principles to tests as you do to your mainline code. Build a domain-specific language of classes and methods to make the tests more expressive. Eliminate duplicated code ruthlessly. Have each test do one thing and name the test method based on what it does
  • Practice TDD. Write the test, have it fail, make it work, then refactor it to make it clean.


Having clean code is a must !!!

回复
NHM Tanveer Hossain Khan

Principal Software Engineer at Click Therapeutics

2 个月

Thanks, DVC. Great collection

Dinis Cruz

Founder @ The Cyber Boardroom, Chief Scientist @ Glasswall, vCISO, vCTO and GenAI expert

2 个月

These are great guidelines, but I would change (and expand) the testing part , which as usual is at the end, to be at the beginning. Why? because every single of the previous recommendations , only scales when a good, effective and usable test framework is in place. In fact, these days I make the business case that the quality and effectiveness of the test framework is more important than the main code. Why? Because of the high yield we get from it and for the fact that, that test infrastructure is what allows and enables good and maintainable code (like the one described in this article) to exist

Nicholas Dierauf

Senior Backend Software Engineer

2 个月

Bravo!

回复

要查看或添加评论,请登录

David Van Couvering的更多文章

  • Simplifying technical designs

    Simplifying technical designs

    Someone recently shared with me that they really appreciate my ability to take a massive, complex problem or design and…

    3 条评论
  • Choosing a backend language, choosing a culture

    Choosing a backend language, choosing a culture

    Somebody was talking to me about choosing a backend programming language for their startup. I was realizing that in…

    2 条评论
  • How big should a service be? The age-old problem

    How big should a service be? The age-old problem

    It happened again. I was in a conversation with a colleague, and they were trying to decide whether to make something a…

    8 条评论
  • Crossing the distributed systems chasm

    Crossing the distributed systems chasm

    A large part of my career has been helping an engineering organization evolve from a single monolithic system that…

    3 条评论
  • Your job on ADD (AI-Driven-Development)

    Your job on ADD (AI-Driven-Development)

    In a recent article I mused about how AI will impact our jobs as software engineers. I was realizing things were…

    8 条评论
  • Deciding how frequently to deploy

    Deciding how frequently to deploy

    I was talking with a colleague last week about whether they should increase or decrease their deploy frequency. They…

    4 条评论
  • Turn out the lights when you leave...

    Turn out the lights when you leave...

    I have been having some interesting conversations with my developer colleagues as they are starting to see how well the…

    3 条评论
  • Politics and sales as a software engineer

    Politics and sales as a software engineer

    Politics and sales can definitely be a dirty business. Some people will say anything if it is to their advantage.

    1 条评论
  • Changing coding habits

    Changing coding habits

    Over the last few years, I have been working with teams trying to help them change their design and coding habits. I am…

    1 条评论
  • So busy but nothing gets done

    So busy but nothing gets done

    In my last post I talked about value streams and how we can use this concept to change how we think about building…

    2 条评论

社区洞察

其他会员也浏览了