Dev curricula

This is a listing of articles about concepts I find essential for any developer to know. This is organized in order of most base structural concepts to most high level concepts and includes good practices, principles, and lists of articles, conference talks and books on software development.

This page is in constant enhancement.

  • Good Practices

    • Reflect the architecture in the code folder structure

      Doing structural encapsulation makes it a lot easier to communicate bounded contexts, dependencies, layers, related functionality and purpose of grouped classes. Close proximity in the tree suggests closer coupling. The top level should reflect the software usage, so it should be named according to the Domain, but in broad encapsulated concepts, because as business evolve the domain details might change. [Mathias Verraes, Robert C. Martin]

      Make the architecture predictable and readable. Once you’ve agreed on an overall architectural structure for your project, make it obvious where the main elements are located. It will reduce time wasted, keep consistency, prevent lost code and avoid unaware code duplication. [Christian Maioli]

    • Clean Code
      • Make the code predictable and readable
        Don’t code “your way”. Just follow your team coding standards. Make your code predictable and easy to read by coding the way people expect. [Christian Maioli]
      • Create small, focused and encapsulated code units
        The approach when breaking a problem down should be to have each section as focused as possible, affecting only local state, without mixing in irrelevant issues, and without side-effects if at all possible. [Christian Maioli]
      • Make it discrete and processable
        Using magic strings, magic array indexes and custom template language features will lead to a more disconnected codebase. [Christian Maioli]
    • Conditionals (if, case)
      • Avoid nested IF statements [Christian Maioli]
      • Avoid ELSE statements [Christian Maioli]
      • Encapsulate the IF condition in a meaningfully named method [Christian Maioli]
      • Blocks inside conditionals should be one line long, a function call which, if named correctly, adds documentary value [Robert C. Martin]
      • Do the exclusionary IFs first, and do early returns from those conditions. That leaves the bulk of the method body to do the expected work. [Matthew W. O’Phinney]
      • Replace conditionals by polymorphism, when you have a conditional that chooses different behavior depending on the type of object.
        Using inheritance: Extract the different behaviors into different subclasses and make the original method abstract. [Misko Hevery]
        Using composition: Extract the different behaviors into different classes and inject the one you want in the original class. [Sandi Metz]
    • Loops
      • Blocks inside loops should be one line long, a function call which, if named correctly, adds documentary value [Robert C. Martin]
    • Naming conventions
      • Name your variables according to the class they contain [Mathias Verraes]
      • Name functions/methods using a verb, according to their context and what they do
        Document the why. Relevant and contextual variable and function names are the way to do this. [Robert C. Martin, Christian Maioli]
      • Name your classes using a noun, according to their domain and architectural meaning [Robert C. Martin]
      • A class name should start by its domain meaning (ie. User) and be postfixed by their architectural meaning (ie. Factory) like UserFactory.
      • A class name should identify it without ambiguity
        Name your classes with a name as unique as possible, regardless of their namespace, so we don’t have to lose our focus from the code to go check the namespace.
    • Functions / methods
      • Should be as small as possible [Robert C. Martin]
      • Should have an explicit intent, both in its name and code [Robert C. Martin]
      • Should do one thing only and do it well. One thing means one level of abstraction (manipulating strings is one level, manipulating business rules is another level), or when nothing else can be extracted and meaningfully reused in another function or method [Robert C. Martin]
      • Methods in a class should be organized per level of abstraction, where the methods used by a method sit directly below it [Robert C. Martin]
      • Choose descriptive names, for small functions, that do one thing [Robert C. Martin]
      • Should have at most 3 arguments, if we have more than 3 and they are conceptually related, we should group them in an object [Robert C. Martin]
      • Do not use output-arguments (arguments to output data out of a function/method) [Robert C. Martin]
      • Don’t use boolean arguments, use 2 functions/methods instead [Robert C. Martin]
      • Comply to CQS, either:
        – Do something (change state)
        – Get something (return info about an object)
        Not both [Robert C. Martin]
      • Don’t return an error code, throw an exception instead [Robert C. Martin, Misko Hevery]
    • Classes
      • Named constructors
        Its OK to use them. [Mathias Verraes]
      • Static methods
        Use them when they are stateless and generic (not domain, so we can have different implementations of domain logic injected in different places)  [Mathias Verraes]
      • Private members access between sibling objects
        It is handy, and OK, to do so in restricted situations, like comparing sibling objects properties.  [Mathias Verraes]
      • Don’t set state by reference
        All state should be encapsulated and inaccessible from outside the object. If we set a property using a given reference, the given object is still accessible from outside. If needed, clone the object being set; [Marco Pivetta]
      • Don’t use setters
        Change in an object state should be the consequence of a conceptual/domain operation applied and encapsulated in the object. The constructor should be the only state injection point. If a business logic only sets a data value, so be it, but don’t name the method as a setter, name it by the business logic it reflects; [Mark Ragazzo, Marco Pivetta, TellDontAsk]
      • Avoid Getters
        Using getters is sometimes necessary, but most of the times they should not be necessary. Their mere existence encourages putting business logic outside the class that has the data necessary to fulfill that logic, breaking encapsulation; [TellDontAsk]
      • Declare class as final
        So it can’t inadvertently break LSP; [Mark Ragazzo, Marco Pivetta]
      • No mixed argument types
        Don’t use an array/collection with different types inside as a parameter; [Marco Pivetta]
      • No mixed return types
        Don’t return an array/collection with different types inside. If needed, use a value object to encapsulate the different types; [Marco Pivetta]
      • No boolean parameters
        A boolean parameter will most likely be a logic switch for the method logic. This means it is actually hiding 2 methods. Then its better to actually have two methods. [Marco Pivetta, Robert C. Martin]
      • NULL objects:
        As an argument
        When a class has an optional dependency on a service, it is common practice to initialize it with NULL. However, it might be more readable and less error prone to initialize that dependency with an object that fulfills the dependency but all its methods just do nothing. This makes it possible to not need to check if the dependency is set and will make sure no errors will occur if someone tries to use a non set dependency; []
        As a return value
        Never return null, return a null object or empty list instead, to reduce the conditionals needed by the client code; [Misko Hevery, Sandi Metz]
      • Composition over inheritance [Sandi Metz]
    • Immutable objects [Mark Ragazzo, Marco Pivetta]
      • When you need to modify an immutable object we actually return a new object with the new state;
      • Declare properties as private so state can’t be modified from outside the object, nor even extending classes;
      • Do not store references to mutable objects or mutable collections, in an immutable object. If we store a collection inside an immutable object, it should be immutable too, including its size, its elements and content of its elements;
      • Declare class as final
        So it can’t be overridden adding methods that modify internal state;
    • Entities
      • They are the same if their ID is the same; [Mathias Verraes]
      • Don’t create/use anemic entities
        Entities should contain logic that manipulates their instances data, inside a specific object and between objects of the same type. However, they should not have knowledge about higher level domain processes. This is a fine line, easy to miss, and involves heavy ponderation and contextualization into the domain concepts; [Ross Tuck]
    • Value objects [Marco Pivetta, Mathias Verraes]
      • They are the same if their state is the same;
      • They ensure consistency, because the data is encapsulated and immutable.
      • They simplify data validation, because we don’t need to validate their data everywhere its needed (its validated when creating the value object);
      • They encapsulate state and behavior (including validation);
    • Exception Handling
    • Business Rules
      • BRs applicable to a Domain Object must be enforced by the object itself. For example, if a Costumer must always have an email, make it impossible to create a Customer entity without an email, by forcing its injection in the constructor; [Mathias Verraes]
      • If a BR should be enforced in a domain object sometimes and sometimes not, maybe we are missing some relevant domain concept, maybe we should be using two different domain objects instead. For example, if a customer sometimes doesn’t need an email and sometimes must have an email, maybe we should have a ProspectiveCustomer and a PayingCustomer entities; [Mathias Verraes]
      • If the verification of a BR needs more than one object (ie an entity and a repository) encapsulate it in a SPECIFICATION object.
      • When using a specification object to model a BR, encapsulate its different representations in the same specification object (ie code and SQL representations); [Mathias Verraes]
      • When using a specification object, test the different representations of the BR by comparing their result against each other; [Mathias Verraes]
    • Modeling the domain
      • Start modeling the domain by defining the use cases (ie addProductToBasket) and from there decide what commands, handlers, services, entities, value objects and repositories are needed; [Mathias Verraes]
    • Talks
  • Principles


2 thoughts on “Dev curricula

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s