Laws, Theories, Principles and Patterns that developers will find useful.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE Create LICENSE Jan 25, 2018
README.md Correct typo reserve/reverse Jan 8, 2019

README.md

hacker-laws

Laws, Theories, Principles and Patterns that developers will find useful.

Introduction

There are lots of laws which people discuss when talking about development. This repository is a reference and overview of some of the most common ones. Please share and submit PRs!

❗: This repo contains an explanation of some laws, principles and patterns, but does not advocate for any of them. Whether they should be applied will always be a matter of debate, and greatly dependent on what you are working on.

Laws

And here we go!

Conway's Law

Conway's Law on Wikipedia

This law suggests that the technical boundaries of a system will reflect the structure of the organisation. It is commonly referred to when looking at organisation improvements, Conway's Law suggests that if an organisation is structured into many small, disconnected units, the software it produces will be. If an organisation is built more around 'verticals' which are orientated around features or services, the software systems will also reflect this.

See also: 'The Spotify Model'.

Hofstadter's Law

Hofstadter's Law on Wikipedia

It always takes longer than you expect, even when you take into account Hofstadter's Law.

You might hear this law referred to when looking at estimates for how long something will take. It seems a truism in software development that we tend to not be very good at accurately estimating how long something will take to deliver.

The Law of Conservation of Complexity (Tesler's Law)

The Law of Conservation of Complexity on Wikipedia

This law states that there is a certain amount of complexity in a system which cannot be reduced.

Some complexity in a system is 'inadvertent'. It is a consequence of poor structure, mistakes, or just bad modeling of a problem to solve. Inadvertent complexity can be reduced (or eliminated). However, some complexity is 'intrinsic' as a consequence of the complexity inherent in the problem being solved. This complexity can be moved, but not eliminated.

One interesting element to this law is the suggestion that even by simplifying the entire system, the intrinsic complexity is not reduced, it is moved to the user, who must behave in a more complex way.

The Law of Triviality

The Law of Triviality on Wikipedia

This law suggests that groups will give far more time and attention to trivial or cosmetic issues rather than serious and substantial ones.

The common fictional example used is that of a committee approving plans for nuclear power plant, who spend the majority of their time discussing the structure of the bike shed, rather than the far more important design for the power plant itself. It can be difficult to give valuable input on discussions about very large, complex topics without a high degree of subject matter expertise or preparation. However, people want to be seen to be contributing valuable input. Hence a tendency to focus too much time on small details, which can be reasoned about easily, but are not necessarily of particular importance.

The fictional example above led to the usage of the term 'Bike Shedding' as an expression for wasting time on trivial details.

The Unix Philosophy

The Unix Philosophy on Wikipedia

The Unix Philosophy is that software components should be small, and focused on doing one specific thing well. This can make it easier to build systems by composing together small, simple, well defined units, rather than using large, complex, multi-purpose programs.

Modern practices like 'Microservice Architecture' can be thought of as an application of this law, where services are small, focused and do one specific thing, allowing complex behaviour to be composed from simple building blocks.

The Spotify Model

The Spotify Model on Spotify Labs

The Spotify Model is an approach to team and organisation structure which has been popularised by 'Spotify'. In this model, teams are organised around features, rather than technologies.

The Spotify Model also popularises the concepts of Tribes, Guilds, Chapters, which are other components of their organisation structure.

Principles

Principles are generally more likely to be guidelines relating to design.

The Robustness Principle (Postel's Law)

The Robustness Principle on Wikipedia

Be conservative in what you do, be liberal in what you accept from others.

Often applied in server application development, this principle states that what you send to others should be as minimal and conformant as possible, but you should be aim to allow non-conformant input if it can be processed.

The goal of this principle is to build systems which are robust, as they can handle poorly formed input if the intent can still be understood. However, there are potentially security implications of accepting malformed input, particularly if the processing of such input is not well tested.

SOLID

This is an acronym, which refers to:

These are key principles in Object-Oriented Programming. Design principles such as these should be able to aid developers build more maintainable systems.

The Single Responsibility Principle

The Single Responsibility Principle on Wikipedia

Every module or class should have a single responsibility only.

The first of the 'SOLID' principles. This principle suggests that modules or classes should do one thing and one thing only. In more practical terms, this means that a single, small change to a feature of a program should require a change in one component only. For example, changing how a password is validated for complexity should require a change in only one part of the program.

Theoretically this should make code more robust, and easier to change. Knowing that a component which is being changed has a single responsibility only means that testing that change should be easier. Using the earlier example, changing the password complexity component should only be able to affect the features which relate to password complexity. It can be much more difficult to reason about the impact of a change to a component which has many responsibilities.

See also:

The Open/Closed Principle

The Open/Closed Principle on Wikipedia

Entities should be open for extension and closed for modification.

The second of the 'SOLID' principles. This principle states that entities (which could be classes, modules, functions and so on) should be able to have their behaviour extended, but that their existing behaviour should not be able to be modified.

As a hypothetical example, imagine a module which is able to turn a Markdown document into HTML. If the module could be extended to handle a newly proposed markdown feature, without modifying the module internals, then it would be open for extension. If the module could not be modified by a consumer so that how existing Markdown features are handled, then it would be closed for modification.

This principle has particular relevance for object-oriented programming, where we may design objects to be easily extended, but would avoid designing objects which can have their existing behaviour changed in unexpected ways.

See also:

The Liskov Substitution Principle

The Liskov Substitution Principle on Wikipedia

It should be possible to replace a type with a subtype, without breaking the system.

The third of the 'SOLID' principles. This principle states that if a component relies on a type, then it should be able to use subtypes of that type, without the system failing or having to know the details of what that subtype is.

As an example, imagine we have a method which reads an XML document from a structure which represents a file. If the method uses a base type 'file', then anything which derives from 'file' should be able to be used in the function. If 'file' supports seeking in reverse, and the xml parser uses that function, but the derived type 'network file' fails when reverse seeking is attempted, then the 'network file' would be violating the principle.

This principle has particular relevance for object-orientated programming, where type hierarchies must be modelled carefully to avoid confusing users of a system.

See also:

The Interface Segregation Principle

The Interface Segregation Principle on Wikipedia

No client should be forced to depend on methods it does not use.

The fourth of the 'SOLID' principles. This principle states that consumers of a component should not depend on functions of that component which it doesn't actually use.

As an example, imagine we have a method which reads an XML document from structure which represents a file. It only needs to read bytes, move forwards or move backwards in the file. If this method needs to be updated because an unrelated feature of the file structure changes (such as an update to the permissions model used to represent file security), then the principle has been invalidated. It would be better for the file to implement a 'seekable-stream' interface, and for the XML reader to use that.

This principle has particular relevance for object-orientated programming, where interfaces, hierarchies and abstract types are used to minimise the coupling between different components. Duck typing is a methodology which enforces this principle by eliminating explicit interfaces.

See also:

The Dependency Inversion Principle

The Dependency Inversion Principle

High level modules should not be dependent on low-level implementations.

The fifth of the 'SOLID' principles. This principle states that higher level orchestrating components should not have to know the details of their dependencies.

As an example, imagine we have a program which read metadata from a website. We would assume that the main component would have to know about a component to download the webpage content, then a component which can read the metadata. If we were to take dependency inversion into account, the main component would depend only on an abstract component which can fetch byte data, and then an abstract component which would be able to read metadata from a byte stream. The main component would not know about TCP/IP, HTTP, HTML, etc.

This principle is complex, as it can seem to 'invert' the expected dependencies of a system (hence the name). In practice, it also means that a separate orchestrating component must ensure the correct implementations of abstract types are used (e.g. in the previous example, something must still provide the metadata reader component a HTTP file downloader and HTML meta tag reader). This then touches on patterns such as Inversion of Control and Dependency Injection.

See also:

TODO

Hi! If you land here, you've clicked on a link to a topic I've not written up yet. Feel free to Raise an Issue requesting more details, or Open a Pull Request to submit your proposed definition of the topic.