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.
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.
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.
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
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
Imagine you have an object User
and this has two public methods:
- name
- 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
).
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.
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.
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.
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 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:
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 PrincipleO
: Open/Closed PrincipleL
: Liskov Substitution PrincipleI
: Interface Segregation PrincipleD
: Dependency Inversion Principle
These principles aim to help you to design and build software that will be easy to maintain and extend.
S
: a class should have one, and only one, reason to changeO
: you should be able to extend a class's behavior, without modifying itL
: derived classes must be substitutable for their base classesI
: make fine grained interfaces that are client specific.D
: depend on abstractions not on concrete implementations
For an example of these principles, then please refer to the following resources: