The Principles of Good Programming

https://java-design-patterns.com/principles/

Every programmer benefits from understanding programming principles and patterns. This overview is a reference for myself, and I've just put it here. Maybe it is of help to you during design, discussion, or review. Please note that it's far from complete, and that you often need to make trade-offs between conflicting principles.

The list was inspired by The Principles of Good Programming. I felt that the list closely, but not completely matches what I would personally put into something similar. Additionally, I wanted a bit more reasoning, details, and links to further resources. Let me know if you have any feedback or suggestions for improvement.

Contents

Generic

KISS (Keep It Simple Stupid)

YAGNI

Do The Simplest Thing That Could Possibly Work

Separation of Concerns

Keep Things DRY

Code For The Maintainer

Avoid Premature Optimization

Boy-Scout Rule

Inter-Module/Class

Minimise Coupling

Law of Demeter

Composition Over Inheritance

Orthogonality

Robustness Principle

Inversion of Control

Module/Class

Maximise Cohesion

Liskov Substitution Principle

Open/Closed Principle

Single Responsibility Principle

Hide Implementation Details

Curly's Law

Encapsulate What Changes

Interface Segregation Principle

Command Query Separation

KISS

Most systems work best if they are kept simple rather than made complex.

Why

Less code takes less time to write, has less bugs, and is easier to modify.

Simplicity is the ultimate sophistication.

It seems that perfection is reached not when there is nothing left to add, but when there is nothing left to take away.

Resources

KISS principle

Keep It Simple Stupid (KISS)

YAGNI

YAGNI stands for "you aren't gonna need it": don't implement something until it is necessary.

Why

Any work that's only used for a feature that's needed tomorrow, means losing effort from features that need to be done for the current iteration.

It leads to code bloat; the software becomes larger and more complicated.

How

Always implement things when you actually need them, never when you just foresee that you need them.

Resources

You Arent Gonna Need It

You’re NOT gonna need it!

You aren't gonna need it

Do The Simplest Thing That Could Possibly Work

Why

Real progress against the real problem is maximized if we just work on what the problem really is.

How

Ask yourself: "What is the simplest thing that could possibly work?"

Resources

Do The Simplest Thing That Could Possibly Work

Separation of Concerns

Separation of concerns is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. For example the business logic of the application is a concern and the user interface is another concern. Changing the user interface should not require changes to business logic and vice versa.

Quoting Edsger W. Dijkstra (1974):

It is what I sometimes have called "the separation of concerns", which, even if not perfectly possible, is yet the only available technique for effective ordering of one's thoughts, that I know of. This is what I mean by "focusing one's attention upon some aspect": it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect's point of view, the other is irrelevant.

Why

Simplify development and maintenance of software applications.

When concerns are well-separated, individual sections can be reused, as well as developed and updated independently.

How

Break program functionality into separate modules that overlap as little as possible.

Resources

Separation of Concerns

Keep things DRY

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Each significant piece of functionality in a program should be implemented in just one place in the source code. Where similar functions are carried out by distinct pieces of code, it is generally beneficial to combine them into one by abstracting out the varying parts.

Why

Duplication (inadvertent or purposeful duplication) can lead to maintenance nightmares, poor factoring, and logical contradictions.

A modification of any single element of a system does not require a change in other logically unrelated elements.

Additionally, elements that are logically related all change predictably and uniformly, and are thus kept in sync.

How

Put business rules, long expressions, if statements, math formulas, metadata, etc. in only one place.

Identify the single, definitive source of every piece of knowledge used in your system, and then use that source to generate applicable instances of that knowledge (code, documentation, tests, etc).

Apply the Rule of three.

Resources

Dont Repeat Yourself

Don't repeat yourself

DRY Principle: Its Benefit and Cost with Examples

Related

Abstraction principle

Once And Only Once is a subset of DRY (also referred to as the goal of refactoring).

Single Source of Truth

A violation of DRY is WET (Write Everything Twice)

Be careful with the code metric "duplicated lines"

Code For The Maintainer

Why

Maintenance is by far the most expensive phase of any project.

How

Be the maintainer.

Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.

Always code and comment in such a way that if someone a few notches junior picks up the code, they will take pleasure in reading and learning from it.

Don't make me think.

Use the Principle of Least Astonishment.

Resources

Code For The Maintainer

The Noble Art of Maintenance Programming

Avoid Premature Optimization

Quoting Donald Knuth:

Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

Understanding what is and isn’t "premature" is critical of course.

Why

It is unknown upfront where the bottlenecks will be.

After optimization, it might be harder to read and thus maintain.

How

Make It Work Make It Right Make It Fast

Don't optimize until you need to, and only after profiling you discover a bottleneck optimise that.

Resources

Program optimization

Premature Optimization

Minimise Coupling

Coupling between modules/components is their degree of mutual interdependence; lower coupling is better. In other words, coupling is the probability that code unit "B" will "break" after an unknown change to code unit "A".

Why

A change in one module usually forces a ripple effect of changes in other modules.

Assembly of modules might require more effort and/or time due to the increased inter-module dependency.

A particular module might be harder to reuse and/or test because dependent modules must be included.

Developers might be afraid to change code because they aren't sure what might be affected.

How

Eliminate, minimise, and reduce complexity of necessary relationships.

By hiding implementation details, coupling is reduced.

Apply the Law of Demeter.

Resources

Coupling

Coupling And Cohesion

Law of Demeter

Don't talk to strangers.

Why

It usually tightens coupling

It might reveal too much implementation details

How

A method of an object may only call methods of:

The object itself.

An argument of the method.

Any object created within the method.

Any direct properties/fields of the object.

Resources

Law of Demeter

The Law of Demeter Is Not A Dot Counting Exercise

Composition Over Inheritance

Why

Less coupling between classes.

Using inheritance, subclasses easily make assumptions, and break LSP.

How

Test for LSP (substitutability) to decide when to inherit.

Compose when there is a "has a" (or "uses a") relationship, inherit when "is a".

Resources

Favor Composition Over Inheritance

Orthogonality

The basic idea of orthogonality is that things that are not related conceptually should not be related in the system.

Source: Be Orthogonal

It is associated with simplicity; the more orthogonal the design, the fewer exceptions. This makes it easier to learn, read and write programs in a programming language. The meaning of an orthogonal feature is independent of context; the key parameters are symmetry and consistency.

Source: Orthogonality

Robustness Principle

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

Collaborating services depend on each others interfaces. Often the interfaces need to evolve causing the other end to receive unspecified data. A naive implementation refuses to collaborate if the received data does not strictly follow the specification. A more sophisticated implementation will still work ignoring the data it does not recognize.

Why

In order to be able to evolve services you need to ensure that a provider can make changes to support new demands while causing minimal breakage to their existing clients.

How

Code that sends commands or data to other machines (or to other programs on the same machine) should conform completely to the specifications, but code that receives input should accept non-conformant input as long as the meaning is clear.

Resources

Robustness Principle in Wikipedia

Tolerant Reader

Inversion of Control

Inversion of Control is also known as the Hollywood Principle, "Don't call us, we'll call you". It is a design principle in which custom-written portions of a computer program receive the flow of control from a generic framework. Inversion of control carries the strong connotation that the reusable code and the problem-specific code are developed independently even though they operate together in an application.

Why

Inversion of control is used to increase modularity of the program and make it extensible.

To decouple the execution of a task from implementation.

To focus a module on the task it is designed for.

To free modules from assumptions about how other systems do what they do and instead rely on contracts.

To prevent side effects when replacing a module.

How

Using Factory pattern

Using Service Locator pattern

Using Dependency Injection

Using contextualized lookup

Using Template Method pattern

Using Strategy pattern

Resources

Inversion of Control in Wikipedia

Inversion of Control Containers and the Dependency Injection pattern

Inversion of Control

Inversion of Control is also known as the Hollywood Principle, "Don't call us, we'll call you". It is a design principle in which custom-written portions of a computer program receive the flow of control from a generic framework. Inversion of control carries the strong connotation that the reusable code and the problem-specific code are developed independently even though they operate together in an application.

Why

Inversion of control is used to increase modularity of the program and make it extensible.

To decouple the execution of a task from implementation.

To focus a module on the task it is designed for.

To free modules from assumptions about how other systems do what they do and instead rely on contracts.

To prevent side effects when replacing a module.

How

Using Factory pattern

Using Service Locator pattern

Using Dependency Injection

Using contextualized lookup

Using Template Method pattern

Using Strategy pattern

Resources

Inversion of Control in Wikipedia

Maximise Cohesion

Cohesion of a single module/component is the degree to which its responsibilities form a meaningful unit; higher cohesion is better.

Why

Increased difficulty in understanding modules.

Increased difficulty in maintaining a system, because logical changes in the domain affect multiple modules, and because changes in one module require changes in related modules.

Increased difficulty in reusing a module because most applications won’t need the random set of operations provided by a module.

How

Group related functionalities sharing a single responsibility (e.g. in a class).

Resources

Cohesion

Coupling And Cohesion

Liskov Substitution Principle

The LSP is all about expected behavior of objects:

Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

Resources

Liskov substitution principle

Liskov Substitution Principle

Open/Closed Principle

Software entities (e.g. classes) should be open for extension, but closed for modification. I.e. such an entity can allow its behavior to be modified without altering its source code.

Why

Improve maintainability and stability by minimizing changes to existing code.

How

Write classes that can be extended (as opposed to classes that can be modified).

Expose only the moving parts that need to change, hide everything else.

Resources

Open Closed Principle

The Open Closed Principle

Single Responsibility Principle

A class should never have more than one reason to change.

Long version: Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. Responsibility can be defined as a reason to change, so a class or module should have one, and only one, reason to change.

Why

Maintainability: changes should be necessary only in one module or class.

How

Apply Curly's Law.

Resources

Single responsibility principle

Hide Implementation Details

A software module hides information (i.e. implementation details) by providing an interface, and not leak any unnecessary information.

Why

When the implementation changes, the interface clients are using does not have to change.

How

Minimize accessibility of classes and members.

Don’t expose member data in public.

Avoid putting private implementation details into a class’s interface.

Decrease coupling to hide more implementation details.

Resources

Information hiding

Curly's Law

Curly's Law is about choosing a single, clearly defined goal for any particular bit of code: Do One Thing.

Curly's Law: Do One Thing

The Rule of One or Curly’s Law

Encapsulate What Changes

A good design identifies the hotspots that are most likely to change and encapsulates them behind an API. When an anticipated change then occurs, the modifications are kept local.

Why

To minimize required modifications when a change occurs

How

Encapsulate the concept that varies behind an API

Possibly separate the varying concept into its own module

Resources

Encapsulate the Concept that Varies

Encapsulate What Varies

Information hiding

Interface Segregation Principle

Reduce fat interfaces into multiple smaller and more specific client specific interfaces. An interface should be more dependent on the code that calls it than the code that implements it.

Why

If a class implements methods that are not needed the caller needs to know about the method implementation of that class. For example if a class implements a method but simply throws then the caller will need to know that this method shouldn't actually be called.

How

Avoid fat interfaces. Classes should never have to implement methods that violate the Single responsibility principle.

Resources

Interface segregation principle

Boy-Scout Rule

The Boy Scouts of America have a simple rule that we can apply to our profession: "Leave the campground cleaner than you found it". The boy-scout rule states that we should always leave the code cleaner than we found it.

Why

When making changes to an existing codebase the code quality tends to degrade, accumulating technical debt. Following the boyscout rule, we should mind the quality with each commit. Technical debt is resisted by continuous refactoring, no matter how small.

How

With each commit make sure it does not degrade the codebase quality.

Any time someone sees some code that isn't as clear as it should be, they should take the opportunity to fix it right there and then.

Resources

Opportunistic Refactoring

Command Query Separation

The Command Query Separation principle states that each method should be either a command that performs an action or a query that returns data to the caller but not both. Asking a question should not modify the answer.

With this principle applied the programmer can code with much more confidence. The query methods can be used anywhere and in any order since they do not mutate the state. With commands one has to be more careful.

Why

By clearly separating methods into queries and commands the programmer can code with additional confidence without knowing each method's implementation details.

How

Implement each method as either a query or a command

Apply naming convention to method names that implies whether the method is a query or a command

Resources

Command Query Separation in Wikipedia

Command Query Separation by Martin Fowler

你可能感兴趣的:(The Principles of Good Programming)