# Principles
# Coding Principles
Clean Code | Clean Architecture |
---|---|
SOLID | Layered |
KISS | Hexagon |
DRY | Onion |
Naming | Horizon |
Coding Convention | CQRS - ES |
Algorithm | Abstraction |
Code Quality | API first approach |
# Keep It Simple, Stupid (KISS)
It means you should be writing code as simple as possible. Don't get caught up in trying to be overly clever or showing off with a paragraph of advanced code. If you can write a script in one line, write it in one line.
# Don't repeat yourself (DRY)
TIP
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
# Principle of Least Surprise (Consistency Principle)
The Principle of Least Surprise is the idea that a user shouldn't be surprised by the way an interaction or object works in an interface or design. This means prioritizing functionality and use over things like consistency to avoid astonishing or surprising your user.
In interface design, always do the least surprising thing. - Eric Steven Raymond, The Art of Unix Programming
# Separation Of Concerns
The separation of concerns principle is an abstract version of the single responsibility principle. This idea states that a program should be designed with different containers, and these containers should not have access to each other.
# You Aren't Going To Need It (YAGNI)
This principle means you should never code for functionality on the chance that you may need in the future. Don't try and solve a problem that doesn't exist.
# SOLID Principles
# Single responsibility priciple (SRP)
An active corollary to Conway's law:
The best structure for a software system is heavily influenced by the social structure of the organization that uses it so that each software module has one, and only one, reason to change.
# Open/Closed principle (OCP)
Open for extension but closed for modification. - Bertrand Meyer made this principle famous in the 1980s.
# Liskov substitution principe (LSP)
In short, this principle says that to build software systems from interchangeable parts, those parts must adhere to a contract that allows those parts to be substituted one for another. - Barbara Liskov’s famous definition of subtypes, from 1988.
# Interface segregation principle (ISP)
This principle advises software designers to avoid depending on things that they don’t use.
# Dependency inversion principle (DIP)
The code that implements high-level policy should not depend on the code that implements low-level details. Rather, details should depend on policies.
# Document Your Code
Try writing a program, leaving it alone for six months, and come back to modify it. You'll be glad you documented your program instead of having to pour over every function to remember how it works. Work on a coding team? Don't frustrate your fellow developers by forcing them to decipher your syntax.
# Component Principles
From Clean Architecture
# Component Cohension
# The Reuse/Release Equivalence Principle
The granular of reuse is the granular of release.
# The Common Closure Principle
The classes in a component should be closed together against the same kinds of changes. A change that affects a component affects all the classes in that component and no other components.
# The Common Reuse Principle
The classes in a component are reused together. If you reuse one of the classes in a component, you reuse them all.
# Component Coupling
# The Acyclic Dependencies Principle
Allow no cycles in the component dependency graph.
# The Stable Dependencies Principle
Depend in the direction of stability.
Stability Metrics
I = Fan-out / (Fan-in + Fan-out)
- I: Instability
- Fan-in: Incomming dependencies
- Fan-out: Outgoing dependencies
The I metric ranges from 0 to 1.
- I = 0 indicates a maximally stable component.
- I = 1 indicates a maximally unstable component.
# The Stable Abstractions Principle
A component should be as abstract as it is stable.
Measuring Abstraction
A = Na / Nc
- A: Abstractness
- Nc: The number of classes in the component
- Na: The number of abstract classes and interfaces in the component
The A metric ranges from 0 to 1.
- A = 0 implies that the component has no abstract classes at all.
- A = 1 implies that the component contains nothing but abstract classes.
# GRASP
GRASP stands for General Responsibility Assignment Software Principles
# Information Expert
Problem: What is a general principle of assigning responsibilities to objects?
Advice
Assign responsibility to the class that has the information needed to fulfill it.
Information expert (the expert principle) is a principle used to determine where to delegate responsibilities such as methods, computed fields, and so on.
# Creator
Problem: Who creates object A?
Advice
Assign class B the responsibility to create object A if one of these is true (the more the better):
- B contains or compositely aggregates A
- B records A
- B closely uses A
- B has the initialising data for A
# Controller
Problem: What first object beyond the UI layer receives and coordinates (“controls”) a system operation?
Advice
Assign the responsibility to an object representing one of these choices:
- Represents the overall “system”, a “root object”, a device that the software is running within, or a major subsystem (these are all variations of a facade controller).
- Represents a use case scenario within which the system operation. Avoid bloated controllers.
# Low coupling
Problem: How to reduce the impact of change?
Advice
Assign responsibilities so that (unnecessary) coupling remains low. Use this principle to evaluate alternatives. Focus on points of realistic instability or evolution.
Drawback: may add additional layers of indirection.
# High cohesion
Problem: How to keep objects focussed, understandable, and manageable, and as a side effect, support Low Coupling?
Advice
Assign responsibilities so that cohesion remains high. Use this to evaluate alternatives.
Read more: Law of Cohesion (opens new window)
# Polymorphism
Problem: How to handle alternatives based on type? How to create pluggable software components?
Advice
When related alternatives or behaviours vary by type (class), assign responsibility for the behaviour — using polymorphic operations— to the types for which the behaviour varies.
Avoid adding flexibility just because you can.
# Indirection
Problem: Where to assign a responsibility, to avoid direct coupling
between two (or more) classes? How to decouple objects so that low coupling is supported and reuse potential remains higher?
Advice
Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled.
# Pure fabrication
Problem: What object should have the responsibility, when you do not want to violate High Cohesion and Low Coupling, or other goals, but solutions offered by Information Expert (for example) are not appropriate?
Advice
Assign a highly cohesive set of responsibilities to an artificial or convenience class that does not represent a domain concept—sometimes invented to support high cohesion, low coupling, and reuse.
# Protected variations
Problem: How to design objects, subsystems, and systems so that the variations or instability in these elements does not have an undesirable impact on other elements?
Advice
Identify points of predicted variation or instability; assign responsibilities to create a stable interface around them.
Interface is used in broadest sense – not just Java interfaces.
# Key Design Principles
Separation of Concerns
Divide the components of system into specific features so that there is no overlapping among the components functionality. This will provide high cohesion and low coupling. This approach avoids the interdependency among components of system which helps in maintaining the system easy.
Single Responsibility Principle
Each and every module of a system should have one specific responsibility, which helps the user to clearly understand the system. It should also help with integration of the component with other components.
Principle of Least Knowledge
Any component or object should not have the knowledge about internal details of other components. This approach avoids interdependency and helps maintainability.
Minimize Large Design Upfront
Minimize large design upfront if the requirements of an application are unclear. If there is a possibility of modifying requirements, then avoid making a large design for whole system.
Do not Repeat the Functionality
Do not repeat functionality specifies that functionality of components should not to be repeated and hence a piece of code should be implemented in one component only. Duplication of functionality within an application can make it difficult to implement changes, decrease clarity, and introduce potential inconsistencies.
Prefer Composition over Inheritance while Reusing the Functionality
Inheritance creates dependency between children and parent classes and hence it blocks the free use of the child classes. In contrast, the composition provides a great level of freedom and reduces the inheritance hierarchies.
Identify Components and Group them in Logical Layers
Identity components and the area of concern that are needed in system to satisfy the requirements. Then group these related components in a logical layer, which will help the user to understand the structure of the system at a high level. Avoid mixing components of different type of concerns in same layer.
Define the Communication Protocol between Layers
Understand how components will communicate with each other which requires a complete knowledge of deployment scenarios and the production environment.
Define Data Format for a Layer
Various components will interact with each other through data format. Do not mix the data formats so that applications are easy to implement, extend, and maintain. Try to keep data format same for a layer, so that various components need not code/decode the data while communicating with each other. It reduces a processing overhead.
System Service Components should be Abstract
Code related to security, communications, or system services like logging, profiling, and configuration should be abstracted in the separate components. Do not mix this code with business logic, as it is easy to extend design and maintain it.
Design Exceptions and Exception Handling Mechanism
Defining exceptions in advance, helps the components to manage errors or unwanted situation in an elegant manner. The exception management will be same throughout the system.
Naming Conventions
Naming conventions should be defined in advance. They provide a consistent model that helps the users to understand the system easily. It is easier for team members to validate code written by others, and hence will increase the maintainability.
# Others
Hollywood Principle "don't call us, we'll call you"
# References
- 10 Basic Programming Principles Every Programmer Must Know (opens new window)
- 10 Coding Principles Every Programmer Should Learn (opens new window)
- GRASP (object-oriented design) (opens new window)
- General Responsibility Assignment Software Patterns (opens new window)
- Design: GRASP and Refinement (opens new window)
- GRASP Design Principles (opens new window)
- Principles of Package and Component Design (opens new window)