Principles - raisercostin/software-wiki GitHub Wiki

Design is a battlefield of multiple acting forces that each drags/push/force the design in a specific way. One some we need to act immediately for some we let them to build pressure and will act later when the decision becomes clearer. Nevertheless is good to understand the stressors.

Design can be learned organically: first learn some fixed forms, after that get rid of them.

The fixed forms are guidelines, principles, philosophies, paradigms, patterns, anti-patterns, idioms, code smells, rules of thumb, adagios, mantras, best practices etc. Some of them applies to the way things are (items and the relationship between them), some of them talk about a process or thinking process (how to move from one state to other). The first are called design principles, the later process principles.

The following is a list of principles that are the highest kind of rules that can guide a novice on resolving situations/tendencies of any type of computing entity: code, components, packages, containers, systems.

Intention First

  • a style of development where you first clarify the intention: what is given, what you need and only then you focus on how (if is really needed)
  • functional is more, is intention only - because implementation is implemented once in the engine and is hidden from sight
    • see SQL, CSS selectors, regex, map/reduce functional collections (hadoop, spark, etc)
  • imperative could be intention first if the method is first defined
    • TDD (Design, Development) also focuses on intention first
  • focusing on intention first you have a good chance of getting rid of all accidental complexity
  • Corollary:
    • Do not add accidental complexity/data (noise)

SRP - Single Responsibility Principle

  • enables composable features

PLS - Principle of Least Surprise

KISS - Keep It Simple

YAGNI - You aint gona need it

DRY - Dont Repeat Yourself

Fix bugs in one place, future reuse and improvements done in one place.

  • http://principles-wiki.net/principles:don_t_repeat_yourself
  • remove magical values (use constants that you can use everywhere). They should represent intent (not the actual value), meaning there might be multiple constant names for same magical value each of them representing different intention.
    • magical value 1. what is a good name for it?
    • magical value 0. what is a good name for it?
    • magical value 400. what is a good name for it?
    • magical value "EUR". what is a good name for it?

Fail Fast

Tell Don't Ask

Hollywood Principle - Don't call us We call you

OCP - Open Closed Principle

A part(component, class, api, schema, server) should be Open for extension, Closed for modification

LSP - Liskov Substitution Principle

DIP - Dependency Inversion Principle / IoC - Inversion of Control

POE - Premature Optimization is Evil

Premature Optimization is the Root of all Evil Optimization is done after a bug is filled with proof that the new code is improving the situation. Use a profiler Connected with YAGNI. Michael A. Jackson

  • The First Rule of Program Optimization: Don't do it.
  • The Second Rule of Program Optimization – For experts only: Don't do it yet.

See also Intro-to-Performance

Let it crash

On software systems in worst case scenario the systems should be able to crash/reboot and continue from where they left.

Uniform Access Principle

The uniform access principle of computer programming was put forth by Bertrand Meyer (originally in Object-Oriented Software Construction). It states "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation".

Composition over Inheritance

Scout Rule

Demeter Law

This "law" is a little more controversial than others. There

  • Parallel: E suficient sa se inteleaga ce inseamna Law of Demeter si impactul asupra designului. Exista forte care complica designul. Exista forte care il simplifica. Daca suntem constienti putem lua decizii mai bune. O paralela ar fi un sistem in care ai masina, jenti, cauciuc, vintil si aer/azot. Daca doar ca sa schimbi din aer in azot trebuie sa schimbi masina sau jentile … ai cam incalcat law of demeter.
  • PRO
  • CONS

CQRS - Command Query (Responsibility) Separation/Segregation

Event sourcing

Ordering - Causality, Time and Happens-Before

You're right in identifying the importance of applying events in order for them to properly reflect the state of the system. This can be a particularly tricky challenge when dealing with distributed systems and multiple data sources. Here are some techniques to address this:

  • Sequence Numbers: They're the most basic way to ensure events are processed in order. Each event gets a unique, incrementing identifier. As long as all components respect the order of these identifiers, they will process the events in the correct sequence.
  • Timestamps: Timestamps are another common way to order events. However, they can be tricky to use correctly due to the risk of clock skew and the difficulty of guaranteeing exact synchronization across distributed systems.
  • Vector Clocks: Vector clocks are an extension of logical clocks and can be used in distributed systems to figure out the order of events. They provide a partial ordering of events based on causality, meaning "Event A happened before Event B". This helps in resolving conflicts when merging events from different sources.
  • Lamport Clocks: Similar to vector clocks, Lamport clocks are a logical clock system used to determine the order of events in a distributed system. It provides a partial ordering of events with the causal ordering property.
  • Global Transaction IDs: In some distributed systems, a global transaction ID is used to order events. This requires more coordination, as every event across the system must be associated with a globally unique ID that also encodes ordering information.
  • Kafka Offsets: If you're using Kafka, it assigns each event a unique, incremental ID called an offset. Kafka guarantees that events within a partition are in the order they were written. However, this order does not extend across partitions.

Conflicting

When merging messages from two independent sources, one approach is to use a Conflict-free Replicated Data Type (CRDT). CRDTs are data structures that allow multiple replicas to be updated independently and concurrently, then merged with a guaranteed mathematically correct outcome.

For deeper insights into these topics, you might want to consider the following resources:

  • "Distributed Systems for Fun and Profit" by Mikito Takada
  • "Designing Data-Intensive Applications" by Martin Kleppmann
  • "Data and Reality" by William Kent
  • The DynamoDB paper from Amazon
  • Blogs and articles by Leslie Lamport, inventor of Lamport Clocks
  • Resources about Apache Kafka for understanding Kafka Offsets

Preserve information

  • Do not destroy/discard information.
  • For example when ignoring properties you might ignore important information that is there but is invisible for software.
    @JsonIgnoreProperties(ignoreUnknown = true)
    public class ServiceResponse {
      public String id;
      public String code;
      //public String message;
    }
    
  • In this case you can use @JsonAnySetter with a map.
    @JsonIgnore
    public Map<String, Object> dynamic = Maps.newTreeMap();
    
    @JsonAnyGetter
    private Map<String, Object> getValues() {
      return dynamic;
    }
    
    @JsonAnySetter
    public void set(String name, Object value) {
      dynamic.put(name, value);
    }
    
  • Sample that breaks
    • Bad
      }catch(Exception e){
        //Do nothing with e
      }
      
    • Best - preserving information existing in exception
      }catch(Exception e){
        log.debug("Ignoring exception but still log if we need to start debug",e);
      }
      
    ⚠️ If this exception is a legitimate business error we inform at debug level. We don't want to log normal business situations with stacktraces. On some circumstances we might want to investigate and need to know full details. Think: what if an NPE is thrown in such try? NPE is not a business error but a development error. So in strange cases we need to be able to enable debug and see what is happening. But in the rest business errors we don't need to log anything.

NIHS - Not Invented Here Syndrome

  • After 20years of professional coding (30 of coding) I still discover myself that I'm breaking this while still thinking that I'm cured. This happens at higher and higher levels. The levels are:
    • loops and functions - assembler, basic didn't have for,while but goto and labels.
      • Use the language instructions.
    • basic data structures and algorithms: lists, maps, arrays, stacks, lists, queues, arrays.
      • Use the language standard libraries
    • advanced data structures and algorithms: multimaps, trees, traversals, graphs
      • Use common libraries.
        • java: guava, vavr, apache commons
    • general problems: configuration, logging, persistence access (database & like), rest api client and server
    • domain specific problems/patterns
      • Read, understand and use code written by colleagues
      • Use libraries used by domain/industry
    • frameworks: web, integration
      • Use frameworks where others already decided on a selection of libraries that go well together.
    • products: email, database
      • Use external self contained products with minimal code changes (plugins)
    • services: search, mail distribution, hosting
      • Use external services/SAAS - no need to invent scalability, maintenance, procedures, etc.
  • https://en.wikipedia.org/wiki/Not_invented_here

Rules - future Principles?

  • Do not add accidental complexity/data (noise)
  • Dumb Code Smart Structures
  • Null is not an Object
  • Array is not an Object
  • Infinite Funds Syndrome (Cost of perfection might be an order of magnitude higher than good enough solution) - The assumption of an engineer that have infinite time & funds to do a perfect software(NASA, Nuclear, Aviation) when a good enough (at a fraction of the costs) will do just fine. Usually engineers that do not keep OCD under control.
    • Solution: focus on effort and impact (ROI - Return Of Investment) = Value Gained Or Impact / Effort Quantified in Both Resources and Time to have Perfect Solution (read The Nature of Software Development)
    • Maximum Impact is limited, Value is effort or negative costs and includes technical debt, lost opportunities and comes from all stakeholders
    • Effort could be infinite
    • image
  • Programming to Interfaces
  • DCSS - Dumb code, smart structures
  • FailFast
  • Elegant Objects
  • Defer Execution - do not compute what is not needed. See functional style.
  • No Code > Good Code > Incomplete Code > Wrong Code (good information > incomplete information > wrong information)
  • Conservative code (open close principle) Do write code to fix your problem/test and only your problem/test. All the other cases should be "fixed" only if they suffer from that bug.
  • Uniform Access Principle

    See also Uniform Access Principle: "uniform access principle The uniform access principle states that variables and parameterless functions should be accessed using the same syntax. Scala supports this principle by not allowing parentheses to be placed at call sites of parameterless functions. As a result, a parameterless function definition can be changed to a val, or vice versa, without affecting client code."

Talk with the duck

Compare

Code smells

  • magical values

References

⚠️ **GitHub.com Fallback** ⚠️