Clean-Code

Pages in this section

  • Checked exceptions
    Last edited: 2023-11-11

    Checked exceptions are a feature of some programming languages, most notably Java , that enforce a strong contract between a method that can fail (throw an exception) and the caller that must handle that failure. When a method might throw a checked exception, the language requires that the method declare this fact in its method signature using a throws clause. Any calling method is then obligated either to catch the exception and handle it or to declare that it, too, throws the exception , propagating it up the call stack.

  • Comment conventions
    Last edited: 2023-11-11

    Comments in code are a necessary evil. As they are not the code, there is no way to check their integrity. As code gets changed the comments may not be updated and can easily cause more confusion that good. Comments also take some thought to process as you need to understand what the person who wrote the comment meant - which is far easier to do in code.

    There are good use cases like a public API or todo notes - though they are mainly there to compensate for our failure to express ourselves in code. They do not make up for bad code!

  • Conventions
    Last edited: 2023-11-11

    Whilst I have written summaries of the conventions from Clean Code and added in some comments about my preferences. The main thing to remember is that the team conventions are the ones that matter. The purpose of conventions is for teams to work better together, when you look at file and your brain doesn’t have to mentally map the code to how to like to read code. The team rules, when it comes to conventions. Whenever you start a new project, get the people who are working on it to agree on a standard and then write what that is down or better implement a Linter to automatically apply the standard when saving or pushing to the common repository.

  • Data - Object Anti-Symmetry
    Last edited: 2026-01-28

    Clean Code

    Objects hide their data behind abstractions and expose functions that operate on that data. Data structures expose their data and have no meaningful functions.

  • Error Handling
    Last edited: 2023-11-11

    To build robust software you must handle things going wrong. In code this comes in the form of error handling. There are many ways of handling errors, some common methods include: exceptions , error codes , and return objects.

    We must build robust code, however this should be done in a way that maintains the readability and reusability of the code. For which there are some helpful principles here.

  • Formatting conventions
    Last edited: 2023-11-11

    Here formatting means the spacing and organisation of files in your code base. This is about communication and leaving a well organised desk space for others to use after you.

    The main metaphor used for formatting is a news paper. Nearly all code is read left to right and top to bottom. You documents, should start with a head line, then as you go down slowly increase in the level of detail. The code should be in nice columns and no story should be too long. It shouldn’t use too much indentation but should be nicely spaced to make it easy to read. You should use paragraphs to break up concepts.

  • Function conventions
    Last edited: 2023-11-11

    Functions should be small encapsulated bits of code that does a single thing. It takes parameters which it does not alter and potentially returns some value or alters the state of the object they belong to.

    # Function body

    # Functions should do one thing

    Function should do one thing, and one thing only. If you need to decide if it is doing more, write out in words what it is doing. If there are sections in your functions, then it for sure is doing too much.

  • Testing conventions
    Last edited: 2023-11-11

    Tests are what makes your code safe to change. They are validate the assumptions that other bits of your code make. Without them you can not change your code without fearing the consequences. Though for this we pay a price with time, time to write them, time to run them and time to maintain them. This is a problem similar to the rest of your code but with different emphasis - tests do not need to be hyper efficient, however they will need to clearly state the assumption that has been broken.

  • The Law of Demeter
    Last edited: 2023-11-11

    This is a heuristic to determine what an object should and shouldn’t know about. It says:

    A method f of an object C should only call the methods of the following:

    • The class C,
    • An object created in f, and
    • An object held in an instance variable of C.

    It should explicitly not call methods on objects that are returned by any of the allowed functions.

    You know this has been violated this when you see Train Wrecks in the code.

  • Train Wrecks
    Last edited: 2023-11-11

    This is a line of code which repeatedly calls different functions on return variables. Like the following:

    object.get_settings().get_graphics_config().get_makers_url().get_abs_path()
    

    Note that they must return a different object, if they are doing permuting objects this a pipe and is more acceptable when doing data manipulation.

  • Wrap 3rd party libraries
    Last edited: 2023-11-11

    It is generally good practice to wrap 3rd party libraries with your own API to be used within your code bases. However, this does come with some downsides. There is a balance between library providers and users and depending on how well they have managed this balance also effects the decision on whether to wrap the library or not.

    # Advantages of Wrapping

    1. API Control: Wrapping allows you to define your own API, giving you greater control over how you interact with the 3rd party library. This can simplify usage and make it easier to implement across your codebase.
    2. Easy Transition: If the 3rd party library becomes obsolete, gets deprecated, or you find a better alternative, wrapping allows you to switch to a different library with minimal effort. You only have to update the wrapper instead of changing every instance where the library is used.
    3. Exception Handling: Wrapping allows you to handle exceptions in a way that’s more aligned with your application’s needs. This can improve robustness and make it easier to debug issues.
    4. Isolation: Wrapping isolates the 3rd party library, making it easier to mock for unit testing, monitor its behaviour, or switch out for a different library.

    # Caveats and Considerations

    1. Overhead: Wrapping adds another layer to your code, which can introduce bugs, increase complexity, and potentially reduce performance.
    2. Maintenance: The wrapper needs to be updated whenever the 3rd party library is updated, especially if there are breaking changes. This can become a maintenance burden over time.
    3. Learning Curve: New team members will need to understand both the wrapper and the underlying library, which can increase the time needed to become productive.
    4. Feature Utilization: It’s easy to create a wrapper that only exposes the subset of the library’s features you initially need, making it harder to take advantage of the library’s full capabilities later on.
    5. Premature Abstraction : For very small projects or prototypes, wrapping might be overkill and could unnecessarily complicate the codebase.

    # Summary

    While wrapping 3rd party libraries can provide benefits in terms of API control, transition ease, and tailored exception handling, it’s essential to weigh these advantages against the potential downsides of increased complexity, maintenance burden, and a steeper learning curve. The decision should be made based on the project’s size, long-term maintenance outlook, and the criticality of the 3rd party library to the application.