Coding guidelines and best practices

Eduard Los
4 min readJan 7, 2020

Code is clean if it can be understood easily — by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability. © Robert Martin
_____________________________________

Some time ago I was involved in a digital transformation process that was going on in the company. Naturally, coding was one of the aspects of that transformation, so when a need in coding standards and best practices arose, I’ve assembled this guidelines. The guidelines below are based on Robert Martin’s book “Clean code”, some of the security best practices and a bit of personal experience. Sometimes it is nice to have such list for a reference when you just joined the company and aren’t familiar with company coding culture.

Recommendations below are rather generic and can be applied to almost any modern language or technology.

General

  • Prefer standard conventions over in-house conventions.
  • Follow KISS and YAGNI principles.
  • Boy-scout rule. Leave the code better than you found it.
  • Keep S.O.L.I.D. principles in mind when writing code.
Single responsibility principle
Open–closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle

Names

  • Use Intention-Revealing Names
  • Make meaningful distinction.
    Distinguish names in such a way that the reader knows what the differences offer.
  • Use pronounceable names.
  • Use searchable names.
  • Replace magic numbers with named constants.
    It is always better to have REQUEST_TIMEOUT isntead of just 60.
  • Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Data, or Info in the name of a class. A class name should not be a verb.

Functions

  • Small.
  • Always do one thing.
  • Use descriptive names.
  • Prefer fewer arguments.
    More than four arguments requires very special case.
  • Should have no unclear side effects.
  • Don’t use flag arguments. Split method into several independent methods that can be called from the client without the flag.
  • Prefer non-static methods to static methods.

Comments

  • Comments Do Not Make Up for Bad Code
  • Always try to make the code itself readable, instead of explaining the intention and functionality with comments.
  • Don’t use obvious, redundant comments.
  • Prefer removing code over just commenting out.
  • Not everything has to be commented/documented.
  • Make documentation for customer facing functionality, when necessary.

Objects and data structures

  • Hide the details of your data structures.
  • Prefer data structures.
  • Avoid hybrids structures (half object and half data).
    Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions.
  • Should be as small as possible.
  • Should follow single responsibility principle.
  • Small number of instance variables.
  • Base classes should not depend on their derivatives.
  • Better to have many functions than to pass some code into a function to select a behavior.

General Design

  • Prefer using dependency injection.
  • if/else or switch/case can create very complicated chains. Prefer polymorphism.
  • Threads should be as independent as possible.
    Consider writing your threaded code such that each thread exists in its own world, sharing no data with any other thread.
  • Prevent over-configurability.
  • Keep configurable data at high levels.
    If you have a constant such as a default or configuration value that is known and reusable, do not hide it in a low-level function, place it in high level instance instead.

Understandability tips

  • Be consistent. If you do something a certain way, do all similar things in the same way.
  • Use explanatory variables.
  • Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
    For example:
    if(level + 1 < totalLevels)
    {
    doSomething(level + 1);
    }


    Notice that level+1 appears twice. This is a boundary condition that should be encapsulated within a variable named something like nextLevel.

    var nextLevel = level + 1;
    if(nextLevel < totalLevels)
    {
    doSomething(nextLevel);
    }
  • Avoid logical dependency. Don’t write methods which work correctly depending on something else in the same class.
  • Minimize negative conditionals. Negatives are just a bit harder to understand then positives.
    if (!customers.orderIds.Any())
    is a bit harder to understand then
    if (customers.orderIds.All())

Security

  • Always validate user input on both Front-End and Back-End.
  • Always sanitize user input fields.
  • Require authentication for all pages and resources, except those specifically intended to be public.
  • Establish and utilize standard, tested, authentication services whenever possible.
  • Validate the authentication data only on completion of all data input, especially for sequential authentication implementations.
  • Use standard session management (don’t create custom session management)
  • Always use strongly typed parameterized queries when working with databases.
  • Utilize input validation and output encoding and be sure to address meta characters. If these fail, do not run the database command.
  • All application modules should fail securely.
  • In case of failure prefer domain models with predefined errors like “Something went wrong” instead of giving the original exception.
  • Do not store sensitive information in logs, including unnecessary system details, session identifiers or passwords.
  • Sanitize all output of un-trusted data before execution.
  • Log all input validation failures.
  • Log all authentication attempts, especially failures.
  • Log all system exceptions.
  • Follow the least privilege rule, when assigning the roles and permissions.
  • Encrypt highly sensitive stored information.
  • Utilize TLS for connections always when possible.
  • Ensure servers, frameworks and system components are running the latest approved version.
  • Check and manage dependencies for vulnerabilities and current versions.

Tests

  • Readable.
  • Fast.
  • Independent.
  • Repeatable.

Code smells

  • Rigidity. The software is difficult to change. A small change causes a cascade of subsequent changes.
  • Fragility. The software breaks in many places due to a single change.
  • Immobility. You cannot reuse parts of the code in other projects because of involved risks and high effort.
  • Needless Complexity.
  • Needless Repetition.
  • Opacity. The code is hard to understand.

--

--