Laws of programming

Laws, theories, principles, and patterns useful to developers


Introduction


Repository translation github.com/dwmkerr/hacker-laws

In discussions related to software development, people often talk about different laws. This repository stores links and descriptions of some of the most famous of them.

It contains explanations of some laws, principles and laws, but there is no agitation in their favor. To use them or not is always a moot point, and it all depends on what you are working on.

The laws


Amdahl's Law


Amdahl’s law is a formula that demonstrates the potential for accelerating a computational task that can be achieved with an increase in the amount of system resources. It is usually used in parallel computing, and can predict the real benefits of increasing the number of processors, taking into account the parallelism limitations of the program.

We give an example. If the program consists of two parts - part A, which must be executed on one processor, and part B, which can be parallelized, it is clear that the advantages of adding several processors to the system executing the program are limited. Potentially, this can greatly accelerate part B - but the speed of part A will not change.

The following diagram shows examples of potential speed gains:



As you can see, even if 50% of the program can be parallelized, the benefits of adding more than 10 separate processors will be negligible. If the program can be parallelized by 95%, the improvements will be noticeable even after adding thousands of processors.

With Moore's Law slowing down and processor speeding up, parallelization becomes the key to improving efficiency. Graphics programming is a great example - modern programming based on shaders allows you to draw fragments of the image in parallel, so in modern graphics cards you can find thousands of processor cores (GPUs or shader modules).

Theory of Broken Windows


The theory of broken windows claims that visible signs of crime (or lack of concern for the environment) entails an increase in the number and severity of crime (and further deterioration of the environment).

This theory has been applied to software development, suggesting that poor code quality (or the so-called " technical debt ") may cause a feeling that all attempts to improve the quality will be ignored or underestimated, which will lead to the appearance of new bad code. This effect develops in cascade, which is why quality deteriorates over time.

Brooks Law


Adding additional human resources to a late project delayed its output even more.


Brooks law says that in many cases, attempts to accelerate the release of a project that is already late by adding additional people to it lead to the fact that the project is released even later than it could. However, Brooks emphasizes that this is an oversimplification of the problem. He reasoned as follows: given the costs of the time required to commission new resources, and the communication of people among themselves, in the short term the development rate of the project falls. Also, many tasks may not be subject to separation, that is, they cannot be easily distributed between resources, the amount of which has been increased, so the potential increase in speed is not so significant.

The common saying "nine women cannot give birth to a baby in one month" refers to Brooks law, in particular because some types of work cannot be divided or parallelized.

This is the main theme of the book Mythical Man-Month.

Conway Law


Conway’s law says that the technical limitations of the designed system will reflect the organization’s structure. He is often remembered when trying to improve the organization. The law says that if an organization is structured into many small, unrelated modules, then the program it creates will be the same. If the organization will be built around verticals, based on certain features or services, then its software will reflect this fact.

Cunningham Law


The best way to find the right answer on the Internet is not to ask a question, but to post a deliberately wrong answer.


Stephen McGeady says that in the early 1980s, Ward Cunningham gave him advice: "The best way to find the right answer on the Internet is not to ask a question, but to post a deliberately wrong answer." McGeady called it "Cunningham's Law," although Cunningham himself denies it and says he is "incorrectly quoted." Although the phrase originally referred to communication on Usenet, the law has since been used to describe work and other communities (Wikipedia, Reddit, Twitter, Facebook).

Dunbar number


The number of Dunbar is a limit on the number of permanent social ties that a person can maintain. This refers to relationships involving knowledge of the distinctive features of a particular individual, the connection with which must be maintained, his character, as well as his social status, and his connections with other people.

The exact number of such relationships is unknown. Dunbar himself suggested that a person can comfortably support no more than 150 such connections. He described it in a more social context: "The number of people you don’t hesitate to join without an invitation to drink together if you accidentally run into them at the bar." Typically, estimates of this number vary from 100 to 250.

Like stable relationships between people, maintaining a programmer’s relationship with code requires a lot of effort. When confronted with large and complex projects or with the ownership of many small ones, we rely on certain agreements, policies and procedures. It is important to consider the Dunbar number not only when increasing the number of employees, but also when determining the scale of the team or the moment when the system should acquire auxiliary tools for modeling and automation of logistics. In the engineering context, this is the number of projects (or the normalized complexity of one project) for which you would confidently be included in the code support group.

Goll law


A working complex system necessarily came from a working simple system. A complex system designed from the ground up never works, and it is impossible to fix it so that it works. You need to start over with a simple working system.


Goll's law suggests that attempts to develop a very complex system will most likely fail. Systems of high complexity are rarely created in one sitting - they evolve from simpler ones.

A classic example is a worldwide network. In the current state, it is a system of high complexity. However, it was initially identified as a simple way to exchange content between institutions. She very successfully coped with these goals and evolved, turning over time into a more complex one.

Goodhart law


Any observed statistical pattern tends to collapse as soon as pressure is exerted on it to control it.


It is also often formulated as:
When a measure becomes a goal, it ceases to be a good measure.
Marilyn Strain


The law states that optimization based on certain measures may lead to the depreciation of these measures. Overly selective measurements (KPIs) blindly applied to a process result in distortion. People strive to optimize the process locally, “deceiving” the system in order to satisfy a certain metric, instead of paying attention to the global result of their actions.

Examples:

  • Tests without claims satisfy expectations for code coverage, despite the fact that such a metric was created so that the program was well tested.
  • Assessing the effectiveness of the developer based on the number of lines contributed to the project leads to unjustified bloating of the code.

Hanlon Razor


Never attribute malice to what is completely explained by stupidity.
The principle states that actions leading to a negative result could be carried out not with bad intentions. The negative result is more likely due to the fact that these actions and their consequences were not well understood.

Hofstader's Law


It always takes more time to complete a task than you expect, even if you took into account the law of Hofstader.

You may come across references to this law when dealing with estimates of the time spent on a project. In the field of software development, it seems a truism that we are not very well able to accurately estimate the time taken to complete the project.

Quote from the book " GĂśdel, Escher, Bach: This Endless Garland ."

Hutber law


Improvement is equivalent to destruction.

This law states that the improvement of one part of the system leads to the destruction of other parts, or hides other types of destruction, which generally leads to degradation of the system compared to its current state.

For example, decreasing the response time in a certain part of the system can lead to an increase in its throughput, and, as a result, to problems with the capacity somewhere in the path of the request flow, which can affect another subsystem.

The cycle of hype and Amar's law


We tend to overestimate the impact of technology in the short term and underestimate it in the long term.

The hype cycle is a visualization of the enthusiasm and development of technology over time, originally built by Gartner. It is best illustrated by the graph:


After the advent of technology, its popularity reaches the peak of bloated expectations, then dives into the depression, rises along the slope of enlightenment and reaches the plateau of productivity

In short, the cycle argues that a fountain of enthusiasm usually arises around new technology and its potential consequences. Teams are often quickly addicted to these technologies and are often disappointed with the results. Perhaps this is because the technology is not yet sufficiently developed, or the methods for its application have not yet been thought out. After a certain time, the capabilities of the technology increase, and the number of practical applications grows, after which the teams can finally become productive.

Hiram's Law


When you reach a sufficient number of API users, it doesn’t matter what features you promised everyone: for any of the possible features of the behavior of your system, there will be a user depending on it.


Hiram's law postulates that if your API has enough users, there will be a user depending on it for any of the possible behavior of your system (not even described in the public contract). A trivial example would be non-functional API features, such as response time. A more subtle example is consumers who rely on determining the type of error by applying the regex function to its description. Even if the public contract does not say anything about the content of the message, and implies that users must use the error code, some of them may decide to use the message, and changing the message will break the API for these users.

Kernigan Law


Debugging code is two times harder than writing it. Therefore, if you write code to the limit of your mental abilities, you, by definition, will not have enough intelligence to debug it.


Kernigan’s law is named after Brian Kernigan and is taken from a book written by him and Plauger: “Elements of a programming style.”

Everyone knows that debugging code is two times harder than writing it. Therefore, if you are doing all your mental efforts when writing code, how are you going to debug it?

Even if the law is a hyperbole, it claims that it is better to use simple code than complicated, since debugging any problems that arise in complex code may be too expensive or even impossible.

Metcalf's Law


In network theory, the usefulness of a network grows roughly like the square of its users.

The law is based on the number of possible pairwise connections within the system, and is closely related to Reed's law. Odlyzhko and others argued that the laws of Reed and Metcalf exaggerated the value of the system, not taking into account the limitations of human ability to understand the network; see Dunbar number.

Moore's Law


The number of transistors placed on an integrated circuit chip doubles approximately every 24 months.

Moore's prediction , which is often used to demonstrate the tremendous speed of improving semiconductor and chip manufacturing technologies, was surprisingly accurate, and worked from the 1970s to the late 2000s. In recent years, the trend has changed slightly, in particular, due to the physical limitations of the miniaturization of components. However, parallelization progress and potentially revolutionary changes in semiconductor technology and quantum computers may mean that Moore's law may remain true for the next few decades.

Murphy's Law


Everything that can go wrong will go wrong.

Murphy's Law, authored by Edward A. Murphy, postulates that anything that can go wrong will necessarily go wrong.

This saying is often used by developers. Sometimes unexpected things happen during development, testing, or even in production. It can be associated with the law of meanness, which is more often used in Britain [in fact, it is also known in Russia / approx. transl.]:
If something can go wrong, it will happen, and in the worst possible moment.

Usually these "laws" are used in a humorous sense. However, phenomena such as confirmation bias and systematic selection error can lead to people being overly keen on these laws (in most cases, when everything works as it should, no one notices this, but failures are more noticeable and attract more discussion).

Occam's razor


You should not multiply things unnecessarily.

Occam’s razor claims that of the few possible solutions, the solution that contains the least amount of concepts and assumptions will be the most likely. This solution will be the simplest and will only solve the given problem without introducing random difficulties and possible negative consequences.

Parkinson's law


Work fills the time allotted to her.

In the original context, the law was based on the study of red tape. Pessimistically, it can be applied to software development, assuming that the team will work inefficiently until the project deadline begins to approach, and then it will be in a hurry to deliver it on time, which makes the specific end date rather arbitrary.

If you combine it with the law of Hofstader, you get an even more pessimistic view: the work will expand until it fills all the time required to complete it, and still takes more than expected.

The effect of premature optimization


Premature optimization is the root of all evil.

In Donald Knuth's work “Structured Programming with GoTo,” he wrote: “Programmers spend a lot of time thinking and worrying about the speed of execution of non-critical parts of programs, and trying to make them more effective has a strong negative effect if you think about debugging and supporting them. We need to forget about the unimportant efficiency of 97% of the time: premature optimization is the root of all evils. However, in critical critical 3% of cases, we should not miss our opportunity. ”

However, premature optimization can also be described as an attempt to optimize something before we understand what we need to do.

Patt Law


The technological sector is dominated by two types of people: those who understand that they do not control, and those who control what they do not understand.


For law Patta often should conclude Patta:
In any technical hierarchy, an inversion of competency is developed over time.

These statements suggest that due to different selection criteria and group organization trends, there will always be a certain number of experienced people at the working levels of the technical organization, and there will always be people at the management level who have no idea about the complexities and problems of the work they manage.

However, it is worth emphasizing that such laws are a very crude generalization, and may be applicable to some types of organizations, and not applicable to others.

Reed's Law


The utility of large networks, especially social networks, scales exponentially with the growth of network size.

This law is based on graph theory, where utility scales as the number of possible subgroups, growing faster than the number of participants or possible pairwise connections. Odlyzhko and others argued that the laws of Reed and Metcalf exaggerated the value of the system, not taking into account the limitations of human ability to understand the network; see Dunbar number.

The law of conservation of complexity (Tesler's Law)


The law states that the system has a certain complexity, which cannot be reduced.

Part of the complexity of the system may occur unintentionally. It is the result of poor structure, errors or unsuccessful modeling of the problem being solved. Inadvertent complexity can be reduced or eliminated. However, some types of complexity are an integral consequence of the complexity of the task itself. This complexity can be moved, but not eliminated.

One of the interesting elements of this law is the assumption that even with the simplification of the entire system, its internal complexity does not decrease, but goes to the user, who has a harder time acting.

The Law of Flowing Abstractions


All non-trivial abstractions are subject to flow to a certain limit.

This law states that abstractions, which are usually used in IT to simplify work with complex systems, in certain situations leak, letting the elements of the systems underlying them flow upward, which is why the abstraction starts to behave unpredictably.

An example is downloading a file and reading its contents. The file system API is an abstraction of lower-level kernel systems, which themselves are an abstraction of the physical processes associated with changing data on a magnetic plate (or in an SSD flash memory). In most cases, an abstraction representing a file as a stream of binary data will work. However, sequential reading of data from a magnetic disk will go faster than random access to them, but SSDs will not have such problems. You need to understand the details lying in depth in order to handle these cases (for example, index database files are structured to reduce random access time), when the abstraction gives a leak of implementation details that the developer needs to know about.

The above example may become more complicated when adding new abstractions. Linux allows you to access files over the network, but they are visible locally as "normal." This abstraction will leak in case of network problems. If the developer treats them as “normal”, not taking into account the fact that they are prone to problems with delays and network failures, his solution will be suboptimal and buggy.

The article describing the law assumes that excessive addiction to abstractions, coupled with poor understanding of the underlying processes, in some cases even complicates the process of solving the problem.

Examples: Slow Photoshop startup. I ran into this problemin past. Photoshop started up very slowly, sometimes it took a few minutes. Apparently, the problem was that at startup it reads information about the current printer by default. But if this printer was a network printer, it could take an extremely long time. The abstraction, according to which the network printer is similar to the local one, caused the user problems in case of poor communication.

Law of triviality


The law states that groups spend much more time and attention on discussing cosmetic or trivial issues than on serious and extensive ones.

Usually, an example is the work of a committee that approves plans for a nuclear power plant, which most of the time discusses the structure of bicycle parking, than the more important issues of the design of the station itself. It can be difficult to make a valuable contribution to the discussion of very large and complex topics without having extensive knowledge on this subject. However, people want to be noted for making valuable comments. From here comes the tendency to concentrate on small details, which are easy to talk about, but which are not necessarily important for the project as a whole.

The fictitious example given above gave rise to the term “bicycle shed effect”, which describes the loss of time in discussing trivial details. There is a similar term, “yak haircut,” which describes a seemingly unrelated activity that is part of a long chain of necessary preparatory steps.

Unix Philosophy


The Unix philosophy is that software components should be small and focus on doing one specific task well. This facilitates the process of building systems by recruiting from small, simple and well-defined modules, instead of using large, complex, multifunctional programs.

Modern practices, such as the “microservice architecture”, can be considered the application of this philosophy - the services are small, focused on one specific task, which allows you to make complex behavior from simple building blocks.

Spotify Model


The approach to team structure and organization that Spotify promotes . In this model, teams are organized around program functions, not around technology.

The model also promotes the concepts of tribes, guilds, branches - other components of the organizational structure.

Wadler's law


In designing any language, the total time spent discussing a feature from this list is proportional to the power of the position number of this feature in the list.
0. Semantics.
1. The syntax.
2. Lexical syntax.
3. The lexical syntax of comments.

That is, for every hour spent on semantics, there are 8 hours spent on the syntax of comments.

Like the law of triviality, Wadler's law postulates that when designing a language, the amount of time spent on language structures is disproportionately large in comparison with the importance of these structures.

Wheaton's Law


Do not be a goat.

This concise, simple and comprehensive law, formulated by Will Wheatan, aims to increase harmony and respect within a professional organization. It can be used in conversations with colleagues, when conducting an expert evaluation of the code, in seeking objections to other points of view, in criticism, and in general, in professional communication between people.

Principles


Principles are most often associated with advice on designing programs.

Dilbert Principle


In companies, there is a tendency to upgrade incompetent employees to managers in order to eliminate them from the work process.

Management concept developed by Scott Adams (creator of Dilbert comics), inspired by Peter’s principle. According to the Dilbert principle , employees who could not be considered competent are promoted to managers in order to limit the possible damage to the company. Adams first explained this principle in an article for the Wall Street Journal in 1995, and then described it in detail in his 1996 book, The Dilbert Principle.

Pareto principle (80/20 rule)


For the most part, everything in life is distributed unevenly.

The Pareto principle states that in some cases a smaller part of the investment is responsible for most of the results:

  • 80% of the program can be written in 20% of the time (and the most difficult 20% take the remaining 80% of the time).
  • 20% of the effort gives 80% of the result.
  • 20% of the work creates 80% of the profit.
  • 20% of errors lead to 80% of program crashes.
  • 20% of the functions are used 80% of the time.

In the 1940s, an American engineer of Romanian origin, Joseph Juran, who is often called the father of quality management, began to apply the Pareto principle to quality problems.

Also, this principle is known, as a rule 80/20, the law of the most important small, the principle of deficiency of factors.

Examples: In 2002, Microsoft reported that after fixing 20% ​​of the most common errors, 80% of the related problems and crashes of Windows and Office will be fixed.

Peter principle


In the hierarchical system, each individual has a tendency to rise to the level of his incompetence.


The managerial concept created by Lawrence Johnston Peter notes the fact that people who do a good job are promoted until they reach a level where they no longer cope (“level of incompetence”). Since they climbed high enough, they are already less likely to be fired (unless they create some kind of complete nonsense), so they will remain in this position, for which they lack the necessary skills, since their behavior skills in the organization do not necessarily coincide with the skills necessary for successful work in this position.

This principle is especially interesting for engineers who start work with purely technical roles, but often build a career leading to the management of other engineers - which requires a completely different set of skills.

The principle of reliability (Postel's law)


Be conservative about your activities, and liberal about the contributions of others.

This principle is often applied to server application development. According to him, the data you send to others should be as small as possible and as good as possible to comply with the standard, but you yourself must accept not entirely standardized data if you manage to process it.

The purpose of the principle is to create reliable systems that can digest poorly formatted data, the meaning of which can still be understood. However, receiving non-standard input data may have consequences associated with a security breach, especially if the receipt of such data has not been well tested.

Over time, the practice of receiving non-standard data may lead to the fact that the protocols will stop developing, as those who implement the exchange of data will begin to rely on the liberality of programs, creating new functions.

SOLID


The acronym for the following 5 principles:

S: The Single Responsibility Principle
O: The Open / Closed Principle
L: The Liskov Substitution Principle
I: The Interface Segregation Principle [ Interface Separation Principle]
D: The Dependency Inversion Principle

These are the key principles of object-oriented programming. Such design principles should help developers create systems that are easier to maintain.

Principle of sole responsibility


Each object must have one responsibility, and this responsibility must be fully encapsulated in the class.

The first of the principles of SOLID. The principle states that each module or class should do only one thing. In practice, this means that a small, single change in the function of a program should require a change in only one component. For example, to change the procedure for checking the password for complexity, the program needs to be fixed in only one place.

Theoretically, this gives the code reliability and simplifies its change. The fact that the component being changed has the sole responsibility should mean that it will be easier to test this change. Changing the password complexity check component from the previous example should only affect functions related to password complexity. It is much more difficult to talk about what will be affected by a component change with many responsibilities.

The principle of openness / closeness


Entities must be open for expansion, but closed for change.

The second of the principles of SOLID. The principle states that entities (classes, modules, functions, etc.) should allow their behavior to be expanded, but their current behavior should not be changed.

A hypothetical example: imagine a module that can turn a Markdown markup document into a HTML markup document. If the module can be expanded so that it learns to handle the new features of the Markdown format without changing its internal functions, then the module is open for expansion. If the module cannot change the processing of the current Markdown functions, then the module is closed for modification.

The principle is especially closely associated with object-oriented programming, where you can design objects that are easy to expand, but you should not design objects whose interiors will change unexpectedly.

Barbara Liskov Substitution Principle


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

The third of the principles of SOLID. The principle states that if a component depends on a type, then it should be possible to use subtypes of this type so that the system does not refuse to work or does not require details of this subtype.

For example, we have a method that reads an XML document from a structure denoting a file. If the method uses the base type file, then the function should be able to use everything that comes from the file. If file supports reverse search, and the XML parser uses this function, but the derived type “network file” refuses to work with reverse search, then the “network file” violates this principle.

The principle is particularly closely related to object-oriented programming, where type hierarchies must be very carefully modeled to avoid confusion for the system user.

Interface separation principle


Software entities should not depend on methods that they do not use.

The fourth of the principles of SOLID. The principle states that consumers of a component should not depend on the functions of a component that it does not use.

For example, we have a method that reads an XML document from a structure denoting a file. It only needs to read bytes, moving forward or backward through the file. If this method has to be updated due to changes in a file structure that is not related to it (for example, due to an update of the access control model representing file security), then this principle will be violated. It is better for the file to implement the "searchable stream" interface, and the XML method to use it.

The principle is particularly closely related to object-oriented programming, where interfaces, hierarchies, and abstract types are used to minimize connections between components. This principle forces the use of duck typing , a methodology that eliminates explicit interfaces.

Dependency Inversion Principle


Upper level modules should not depend on lower level modules.

Fifth of the principles of SOLID. The principle states that control components of higher levels should not know the details of the implementation of their dependencies.

For example, we have a program that reads metadata from a website. Presumably, its main component should be aware of a component that downloads the content of a web page, and a component that reads metadata. If we take into account the principle of dependency inversion, then the main component will depend only on the abstract component receiving byte data, and it, in turn, on the abstract component that can read metadata from the byte stream. The main component will not know anything about TCP / IP, HTTP, HTML, etc.

The principle is rather complicated, since it inverts the expected dependence in the system. In practice, it also means that a separate control component must guarantee the correct implementation of abstract types (in the previous example, something must supply the component metadata reader for downloading the file via HTTP and for reading data from the meta HTML tag).

Don't Repeat Yourself Principle


Each piece of knowledge should have a unique, consistent and authoritative representation within the system.

Don't repeat yourself , or DRY, helps developers reduce code repeatability and keep information in one place. It was mentioned in 1999 by Andy Hunt and Dave Thomas in their book Pragmatic Programmer.

The opposite of the DRY principle dry] should be the principle of WET wet] - “Write Everything Twice” or “We Like Typing” [We Enjoy Typing].

In practice, if the same information is duplicated in you in two or more places, use the DRY principle, merging them into one place and reusing them as necessary.

KISS Principle


Keep it simple, stupid [Don’t complicate, fool]

The KISS principle says that most systems work better if they are not complicated; therefore, simplicity should be a key goal in development, and unnecessary complexity should be avoided. It originated in the U.S. Navy in 1960, and the phrase is attributed to aircraft designer Clarence Johnson.

It is best to imagine it using an example when Johnson gave a small set of tools to a team of design engineers and instructed them to design a plane so that an average mechanic could fix it in a field in battle using only this set. Here stupid denotes the relationship between how things break down and the complexity of the tools available to repair them, rather than the mental abilities of engineers.

YAGNI


Acronym for You Ain't Gonna Need It [you won’t need it].
Always implement functions only when you really need them, and not when you think you need them in the future.

Ron Jeffries , the author of extreme programming techniques (XP) and the book “Installed Extreme Programming,” suggests that developers should only implement the functionality that is needed right now and not try to predict the future by implementing functionality that may be needed later.

Following this principle should reduce the amount of unused code in the database, as well as the waste of time and energy on functionality that does not bring benefits.

Misconceptions of Distributed Computing


Also known as the fallacies of network computing. This is a list of assumptions regarding distributed computing that can lead to software failures. These are the following assumptions:

  1. The network is reliable.
  2. The delay is zero.
  3. The bandwidth is endless.
  4. The network is secure.
  5. The topology does not change.
  6. There is only one administrator.
  7. Shipping cost is zero.
  8. The network is homogeneous.

The first four were listed by Bill Joy and Tom Lyon in 1991, and James Gosling first classified them as "Network Computing Misconceptions." Peter Deutsch added the 5th, 6th and 7th delusion. In the late 90s, Gosling added the 8th.

A group of engineers was inspired by the processes taking place at that time at Sun Microsystems.

These errors should be carefully considered when developing reliable code. Each of the errors can lead to incorrect logic, unable to cope with the reality and complexity of distributed systems.

All Articles