Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save MicFin/aae4aee897a7d6c88309076adf7c6ba6 to your computer and use it in GitHub Desktop.
Save MicFin/aae4aee897a7d6c88309076adf7c6ba6 to your computer and use it in GitHub Desktop.
Coding Best Practices: High Level Principles

High Level Principles

The following principles are very 'high-level' and meant to be used as a quick reference guide, as apposed to the other standards/guideline documents which will focus on specific language idioms and design patterns.

Iceberg Classes

An 'iceberg' class is one that has more private methods than public. Typically what happens is the developer builds the class and exposes only the methods that they feel should be public, whilst all implementation details are hidden away in the private methods.

Problem

This is fine until it comes to testing (this is especially prevalent when not doing test-driven development; i.e. writing tests after the class has been created) where by you want to verify specific behaviour works as expected but you're unable to because your behaviour is locked away in private methods.

Developers will typically try to either hack around the problem or inject additional context into the class, which makes sense in the test environment but not when the code is run in production.

Solution

The solution to this problem is to group together related private behaviour and extract it into a separate class. Naming this new class can be tricky though, as the new class is no longer a noun/object, it is instead very much behavioural (verb/action). If this is proving to be a problem or a concern, then maybe consider instead of creating a class you create a reusable module and include it as runtime instance methods.

e.g. Ruby offers the ability to mixin behaviour via an include statement

Law of Demeter

The 'Law of Demeter' simply states that you should reduce the coupling between objects by identifying when you have a thread of context between them. This particular principle has the following rules:

  • Your method can call other methods in its class directly
  • Your method can call methods on its own fields directly (but not on the fields’ fields)
  • When your method takes parameters, your method can call methods on those parameters directly
  • When your method creates local objects, that method can call methods on the local objects

Problem

Imagine you have an object User and this has two public methods:

  1. name
  2. department

You might have a class that calls User and tries to extract their name as well as their department details.

This could potentially (depending on implementation) be a violation of the law of demeter:

def user_info(user)
  "Name: #{user.name}. Dept: #{user.department.name}"
end

In the above example we're violating the law of demeter because we're accessing a field's field (e.g. we send a message to user.department and then act on its result by trying to access the nested field name).

Solution

The User class should be modified to expose the department name rather than having an external class/object try to nest inside a data structure to extract that data. In other words, User class should have a department_name method that knows the context of its own data and exposes it to any consumers of the User class.

Don't Repeat Yourself

Most people know the concept of "Don't Repeat Yourself" as the DRY principle.

In essence it applies to all forms of design, not just code (e.g. architecture, databases, documentation etc), but we'll consider the principle from the point of view of a programmer for now.

Problem

You've written some behaviour, or business logic, and you realise that implementation could be used within one or more unrelated areas of your codebase.

Solution

Move the behaviour/logic into a function, class or module (whatever makes sense for the programming style you write) and make it a reusable entity by injecting its dependencies (e.g. any external references).

Design Patterns

Design Patterns are - as the name suggest - a common design/architecture/code 'pattern' that can be applied to a problem in a generalised way. These patterns are typically very abstract and that is their purpose.

The mistake most people make when learning about design patterns is assuming that they are an explicit solution to a particular problem. They are not. You need to consider the pattern being described and implement the pattern however you feel best suits the problem you're trying to solve.

There are many official † and unofficial 'design patterns', and in some cases there are concepts (such as S.O.L.I.D - see next section) that sometimes are mistaken for design patterns but really are just coding principles.

† by 'official' I refer to the classic tech book "Design patterns: elements of reusable object-oriented software" and was co-authored by four different people. It is nowadays recognised as being authored by the "Gang of Four" and their described patterns are generally known as the "GoF design patterns"

For a list of creational, structural and behavioural design patterns we highly recommend the following resource:

Here are some common design patterns you might want to start learning about initially:

S.O.L.I.D

The S.O.L.I.D principles were named by Robert C. Martin (highly respected software engineer and co-author of the Agile Manifesto).

  • S: Single Responsibility Principle
  • O: Open/Closed Principle
  • L: Liskov Substitution Principle
  • I: Interface Segregation Principle
  • D: Dependency Inversion Principle

These principles aim to help you to design and build software that will be easy to maintain and extend.

Summary of Principles

  • S: a class should have one, and only one, reason to change
  • O: you should be able to extend a class's behavior, without modifying it
  • L: derived classes must be substitutable for their base classes
  • I: make fine grained interfaces that are client specific.
  • D: depend on abstractions not on concrete implementations

References

For an example of these principles, then please refer to the following resources:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment