Please enable JavaScript.
Coggle requires JavaScript to display documents.
Software - Coggle Diagram
Software
Information hiding/Law of Demeter/Independent State
Pull complexity downwards/don't pass complexity upwards
Lower level methods should not have conceptual knowledge of higher level methods (NOTE: one way to catch this is to ensure lower level is truly reusable- if its not then it likely is not abstracted away from higher level concepts)
Avoid hard-coded references- eg. pathological connections- values that bind internal functionality to external values/make it harder to change in the future
Use Contract Design- The design philosophy that yields greater reliability is the one that requires every function to protect itself, validating its own data.
If you need to change an object’s state, get the object to do it for you. This way your code remains isolated from the other code’s implementation and increases the chances that you’ll remain orthogonal.
Law of Demeter
is a way to decouple objects- ex. ask an object to do the job you want for you (vs. manipulating the object directly).
Promote use of interchangability/portability- for example, use of abstract resource accessors vs. direct integration to external providers (eg. abstract database class)
Defining preconditions for methods allows the caller to validate the parameters to the method
Don't define try-except in the caller- this is coupling (caller has to know about internal state of the method) - allow errors to propagate from the method
Unclosed transactions are a type of coupled state - Transactional activity can be managed in context managers - provides "open" and "close" steps to allocate and deallocate
Methods should "hide" information from callers as much as possible
Any mutable external resource is global data. This includes things like shared databases. If it is important enough to be global- wrap it in an API to decouple the global state from its calling interface
Sharing global state can be problematic due to coupling, but is less problematic when the "state" is read/write data- with a fixed schema especially when passed in a sequential pipeline
Use composition/mixins instead of inheritance. single level inheritance can be nice for defining interfaces.
Actors Model: One way to design away concurrency issues is to make the workers stateless (ie they have everything they need to react in messages passed in their inbox)
Code has
contracts
: you meet the conditions when you feed it input, and it will make certain guarantees about the outputs it produces. There are also code invariants, things that remain true about some piece of state when it’s passed through a function. For example, if you sort a list, the result will have the same number of elements as the original—the length is invariant.
Caller-method Relationship- caller should stick to/prepare data to a strict interface for the method- ie the method should not have to know things outside of its scope to handle more input
Deep modules, less unique interfaces
A little copying is better than a little dependency
The architecture should never depend on a particular version of a commercial product or tool. If it must, it should be structured so that changing to a di erent version is straightforward and inexpensive
Postel's Law: Be conservative in what you send, be liberal in what you accept
Be strict in your outputs- keep them consistent, correct, AND simple. Any violations of these principles overburdens consumers.
Design input validation for only what you truly are dependent on and design input handling to allow things that could change to do so within reason.
Technical Leadership & Teams
Operators should be engineers - The pilot of an airplane should also be a mechanic
Software rot, not technical debt
Build teams that can build end-to-end? Automate repetitive and standardized activities.
Technical leaders should be engineers - The surgical team lead is a surgeon, not a hospital admin
A software (or system) architecture should be the product of a single architect or a small group of architects with an identi ed technical leader.
Turn this Ship Around
Two extremes: A leader giving all orders, being in the middle, full authority vs. leader trying to devolve all decision making to crew, but crew make "bad" decisions- both lead to failures
Simply exhorting people to be proactive, take ownership, be involved, and all the other aspects of an empowerment program only scratches the surface of a leader's responsibility in leader-leader
Give specific goals (the "why"/"what") and do not be prescriptive in the "how" is key to providing correct input to subordinates
Rely on your direct reports for deep details- in order to pay attention to what
they
know- not what
you
know
Focusing on error reduction is wrong- people will always make mistakes- good is not absence of failure- good is going beyond, also anticipating error-prone processes and fixing them
Push control downwards- unnecessary escalation undermines lower level agency. If worried about competency of subordinates or the clarity of goals- both of these can be addressed by the leader
Act your way to new thinking- change behaviors to encourage more productive thinking even if everyone doesn't understand the philosophy yet
Its common to be in case of the workers’ being technically competent but unclear about what we were trying to achieve
Short, early conversations are key to helper workers maintain control/autonomy
Have subordinates state intentions with active language (I intend to, etc). Have subordinates package information so boss can give simple approval or not.
As the level of control is divested, it becomes more and more important that the team be aligned with the goal of the organization
Resist the urge to immediately provide solutions- allow lower level to problem solve first
Eliminate top-down monitoring systems- eg. having leaders track status- devolve responsibilities to lower levels to manage the status, etc- improve the process "is better than" monitor the process
Think out loud- encourage informal communications as a way to share information and prevent things being missed by solely using formal communication
Embrace inspectors- use them as learning moments- opportunities to grow
Act deliberately- Japanese train conductor tie-in: state out-load what action about to perform
Don't brief, certify- ie ask questions that engage participants- don't just lecture
Don't be afraid to
repeat
the message (a lot) on principles you are trying to change (same with goals- hard not to make them "too" clear)
Make it so higher ups are no better off than worst of their subordinates (Ex. take same amount of watch duty as worst-off subordinate)
Build trust with your people by providing them all the tools to succeed- ex. make advancement processes transparent and require/incentive them to do the things that will get them promoted.
Goal is leader-leader approach, not leader-follower
Leaders benefit when they provide clear guidance, enabling teams to anticipate decisions without constant escalation. Define expectations to create a smooth workflow, making subordinates ideal candidates for promotion due to leader-aligned thinking.
It is easier to push our own hard work of changing behavior onto others- when we should consider how we can change to effect differences from others
Groups are more efficient/effective the more equal distribution of speaking between all members
If the most powerful person speaks first- the group will adapt their opinions around that person. If people are asked to conceive their opinions before the powerful person speaks- then you get true wisdom of the crowd/ divergent thinking
For greater diversity of ideas: vote first, then discuss to avoid anchoring bias
Allow for an Andon cord- ability for team to raise a pause if something is off or concerning- ability to disrupt redwork
Give information, not instructions. I will start at 10am not Be back at 10am
Giving people a why- involving them in decision-making gives them more engagement and ownership over the outcome
Offer praise by observing the visible things the other person could control. Instead of "you are so smart", say "it looks like you developed an effective process for overcoming challenges!"
Chunk work and celebrate completions before moving on
Squeamishness about decision-making reflects low psychological safety and error handling. In blame-driven cultures, reluctance to be the decision-maker hinders progress. In contrast, organizations valuing decisions as outcomes of incentives find it less threatening to identify decision-makers
Identify and balance red work vs. blue work- executing on clear plan/tasklist vs. stopping and thinking or analyzing to determine options
Google Project Oxygen
IS a good coach, empowers-not micromanage, expresses concern for wellbeing, Productive and results-oriented, good communicator, prioritizes career development, has clear vision, has technical knowhow
Volatility/Abstraction for general-purpose/Orthogonality/Evolvability/Plasticity
Goal of software design is to encapsulate volatility
Don't design to first set of concrete requirements, design to the abstract "axes" of volatility the concrete requirements represent
Better designs will priortize abstracting and encapsulating areas of volatility they change the most frequently -> leads to general purpose usage
Common axes of volatility
Same user over time
Multiple different users at the same time
Use of specific frameworks/external resources
after-the-fact modularization is nearly impossible to do well
Anticipating bugs and analyzing for change volatility are on the same spectrum- Righting Software's volatility analysis (and test design) can also be addressed by the perspective of what changes/variability is most likely to cause bugs
Ideal Number of Abstractions- Humans have the capacity to mentally juggle about 7±2 entities
coupling & cohesion- the goal is to create a small set of abstractions (eg. classes) that are semantically independent (ie. can be understood on their own- not dependent on other abstractions) and are cohesive (minimal number of simple interfaces to other abstractions) <- Deep abstractions
Fan-in principle- each abstraction should reduce complexity
Variation in the data processed by a system has greatest impact on its reliability
A thing is well designed if it adapts to the people who use it. For code, that means it must adapt by changing. So we believe in the ETC principle: Easier to Change. ETC. That’s it.”
Two or more things are orthogonal if changes in one do not affect any of the others. In a well-designed system, the database code will be orthogonal to the user interface
General purpose interfaces/solutions
Write abstractions against specific resources- generic database vs. specifically whatever flavor of SQL/vendor of the day
Desigining for volatility encourages local changes are the most desirable, so an e ffective architecture is one in which the most common changes are local, and hence easy to make
It’s programming if ‘clever’ is a compliment, but it’s software engineering if ‘clever’ is an accusation.
Software is sustainable when, for the expected life span of the code, we are capable of responding to changes in dependencies, technology, or product requirements. We may choose to not change things, but we need to be capable.
Sources
Righting Software
Rickover
Structured Design
Pragmatic Programmer
Philosophy of Software Design
Designing-Data Intensive Applications
Software Architecture in Practice
Leadership Is Language
Turn this Ship Around
The Politics of Promotion
Smart Brevity
Observability/Testing/Validation
Don't take the obvious for granted. If it is important, you'd better check it out, along with the minutiae
Effective systems allow a single man to check/produce his own work effectively
Test "State" coverage, not code coverage- ie. test the application in its various states of processing- not lines of code
You get what you inspect, not expect
provide fully featured non-production sandbox environments where people can explore and experiment safely, using real data, without affecting real users.
End metrics/KPI/SLA- A quality attribute (QA) is a measurable or testable property of a system that is used to indicate how well the system satis es the needs of its stakeholders beyond the basic function of the system
Use the concept of a checklist- pilots use them to great effect- read-do checklists allow you to read instruction and do the step
Use Prepare-Test-Asset model of structuring unit tests
As useful as static code analysis is, false positives come with the territory. It’s okay to disable rules or suppress specific warnings, but don’t do this lightly. At least, document why you decide to do it, and if possible, get feedback on the decision.”
If you like it then you better put CI on it. Deployment and infrastructure changes should be safe to do. If such as change breaks the code- this is not a fault of the deployer- rather it is the responsibility of the app team to have sufficient tests in CI
A unit test should be "hermetic"- contains all the context/info needed to run the test in its definition.
Readability Optimization
Choose good variable names
Prefer external domain languages (eg. YAML, JSON, etc) over internal ones (eg. Python, Ruby, etc). Internal languages bind your declaration to the limitations of the language syntax (less portable)
the best requirements documentation, perhaps the only requirements documentation, is working code
Write comments early and often (esp. about why/purpose)
The problem is that familiarity is not the same as simplicity. They feel the same — that same ease of moving through a space without much mental effort — but for very different reasons. Every “clever” (read: “self-indulgent”) and non-idiomatic trick you use incurs a learning penalty for everyone else.
You will read code more often than your write it- optimize for readability
"what you see is what there is" principle for keeping key related information in what place
Use variable naming instead of inline comments to clarify something's intent
Company wikis do not not get used. Better to use source control, have automations that watch last update times for docs, and allow readers to petition for changes like bug reports
Politics
The more senior you become the more your job progression is based on politics
Know how has influence (regardless of title)
Know what the cultural preferences are
Know what gets rewarded vs. ignored
Develop a reputation for making influential people's life easier
Over-share your accomplishments
Always be part of the solution
Consider the use of coaches to guide your career
Communications
Extra words are cowardice- brevity is confidence
“If we don’t really know what we want to say—or more likely, if we don’t really understand what we’re writing about—we paper over it by saying too much.”
Isolate the one thing you want the reader to take away- make it a data point
List the points you MUST make
Whittle down to at most 2 points
Omit secondary benefits- stick with the most important benefit- the rest fall away
Add an axiom- "Why it matters"
Avoid subjunctive and passive voice.
The Engineering Professional's Ideals
High Ownership yields High Responsibility means leave it better than you found it
Total responsibility in each individual- that he is personally responsible, not only for his own specific part of the job, but for everything we do.
Ownership is the highest virtue- own what you build forever, demanding highest excellence while having the attitude that at any second it may not be yours but the next owner is just as demanding
Programming is about making the future less painful
Broken window philosophy- neglected code breeds more neglect- pristine code breeds more clean code
Know about your own shop than your boss or any one else
Restrict design alternatives to channel the creativity of developers, reducing design and system complexity
Reliability/Continuous Flow/Fault tolerant Architecture
If there is an error, something very, very bad has
happened
Assertions (or other methods) can be useful for "failing" early (inside the method)
We can wrap data in metadata that indicates if the data is valid or not (error channel). Then, callers or downstream methods can reactive to this simple valid or not information.
Define errors out of existance
Because the work of people is almost always more expensive error-prone than the work of computers, letting computers handle a change as much as possible will almost always reduce the cost of making that change
Have zero tolerance for complier/linting warnings- treat them as true errors
Common Architectures
Hierarchy of Software Components
Manager <- Volatility of Workflow = what steps in what order
Engine <- Volatility of Business Rules = How do we accomplish the steps?
ResourceAccess <- Volatility of Resource Interaction/Interface
Resource <- Volatility of Resource Implementation
Ideal ratios: 1 Client has 1 Manager, 0:N Managers have N Engines/ResourceAccess, 0:N Engines have N Resource Access, 1 Resource has 1 ResourceAccess
Depending on complexity of use case can abstract Resource to ResourceAccess later
Client - Presentation - Point of Entry <- Volatility of Interface/Caller
Parallelism is running at exact same time; Concurrency is allowing interrupts to switch between one or more things so they are all "running" non-sequentially
Incremental implementation - One way to do this is via the creation of a “skeletal” system in which the communication paths are exercised but which at rst has minimal functionality
Reversability
Temporal coupling happens when your code imposes a sequence on things that is not required to solve the problem at hand
Where relevant- reversibility is just as important as decoupling, and cohesion
Scaling
An architecture that scales well for a particular application is built around assump‐ tions of which operations will be common and which will be rare—the load parame‐ ters
Version 0
Bjorn suggests achieving consistent 'vertical slicing' by creating a 'Version 0' or a 'walking skeleton'—a minimal yet structurally complete system that connects all components, though functionally rudimentary.