Skip to content

Instantly share code, notes, and snippets.

@tp-hk
Last active April 12, 2025 21:38
Show Gist options
  • Save tp-hk/6b81247b7475094f3985e6d0d2ace5c1 to your computer and use it in GitHub Desktop.
Save tp-hk/6b81247b7475094f3985e6d0d2ace5c1 to your computer and use it in GitHub Desktop.
Tech Books Summary

Somewhat curated sumamries of technical materials. Take it with a grain of salt

Clean Architecture (2022 H2)

Good architecture:

  • good architecture = allow changes w/ flexibility + delay decision

Business rules:

  • Entities: pure; small sets of critical business rules. Should be most independent & reusable. Can be an object with methods or data structures & functions
  • Use case: not as pure; is an object. contains data elements & operations.
  • Entities are lower level than (don’t depend on) use cases since use cases are closer to inputs/outputs.
  • Entities & use cases are 2 layers
  • Returned data structure should not reference entities since they might change for diff. reasons

Screaming architecture:

  • System should describe what it does not what framework it uses

The clean architecture:

  • Use case layer contains application-layer biz rules. Changes at this layer shouldn’t affect entity layer
  • Changes to workflow requires updating use case layer
  • Adapter layer: convert data from/to use cases & entities to/from external (web/DB). Example: Views and controllers in MVC; other data from/to internal/external form
  • Dependency rule: Dependency should point inward (lower level layers)
  • If need to call from inner to outer layer, inner should call an interface implemented by outer layer. Both inner & outer will depend on (point to) interface
  • Data crossing boundaries should be simple or just function args (no entities)
  • Interface adapters: covert data from format of inner layer to the format of external layer

Presenters and humble objects:

  • Presenter accepts data from application and applies formatting. Presenters are testable
  • View (humble object) receive view model from presenters w/o processing. Views display the data
  • Humble object patterns separates testable (non-humble) and non-testable (humble) parts
  • Objects are not data structure. Objects is a set of operations (pubic methods). DS has no behaviors
  • Humble object pattern is likely found in every architectural boundary

Monolith to Microservices (2023 H1)


1 Just Enough Microservices

...

2 Planning a Migration

  • MS is not the goal, goal might be e.g. faster delivery, team automany, break off from monolith release cycle. Need ROI calculation, ned to align with what business tries to achieve
  • Consider microservice alternatives, or try things in parallel. Alternative ideas:
    • Modular monolith
    • Vertical scaling (more powerful machine)
    • Horizontal scaling (more machines)
    • Scale up development team
    • New technology
    • Use sliders to analyze competing priorities
  • Faster delivery: should run path-to-production analysis to find the biggest blocker
  • MS: Benefits
    • More robust architecture (ability to react to expected variations) because of decomposed functionality
    • Great options for scale-up after initial success
  • MS: When's MS a bad idea
    • Unclear domain/decompose prematurely
    • Startup/greenfield project
    • Customer-installed software
    • Lack of good reason
  • Incremental migration:
    • Start somewhat small
    • The impact of decomposition will be relfected in production env, not during development
    • Easier places to experiment - start with whiteboarding
  • Where to start migration/decomposiition
    1. Develop domain model with just enough info (e.g. use event-storming)
    2. identify bounded context
    3. BC is good starting points for defining MS boundaries
    4. map out BC dependencies to determind which is easier to extract (Fig 2.6)
    5. caveat: domain model represents logical view, not how code is organized
    6. Use trade-off diagram (benefit of decomposition vs ease of decomposition) to prioritize decomposiition (Fig 2.8)
  • Reorganizing teams
    • DevOps (independent, autonumous teams)
    • Changing/improving developer skills
  • How to know if transition is working
    • Define measures to track
    • Regular checkpoints (review quantitative + qualitative measures)
    • Quantitative measures e.g. number of deployments, failure rates, cycle time
    • Qualitative measures e.g. team's feelings
    • Avoid sunk cost fallacy
    • Key: take small steps, be open to new approaches
  • Misc.
    • "Reuse is not a direct outcome people want. Reuse is something people hope will lead to other benefits"
    • Irreversible vs reversible decisions

3 Splitting the monolith

  • Do migration over small steps, allow going back if needed. For each step, copy code instead of changing functionality
  • First thing to consider is whether monolith will be modified (more flexibility).
  • Biggest barrier is code isn't organized around business domains. Can use seam - a seam is a defined around the code to chnage, then work on new implementation, and swap after change has been made.
  • Rewrite - try salvage existing codebase first. If not, rewrite small pieces of functionality at a time and release regularly.
  • Migration patterns: Strangler fig application
    • New & old systems coexist, allow new code to grow incrementatlly and eventually replace old system. Easy rollback if required.
    • Useful when: no need to touch existing system/existing system is black box, works well wehn functionality to move isn't deep inside system. Existing code can still be worked on by others.
    • Steps:
      • 1: Identify asset to move
      • 2: Start implmentating new functionality in microservice. Deploy but not released to public. Parallel run with old code
      • 3: Redirect calls to microservice. Prereq: need to have clear inbound calls. If not, consider Branch by Abstraction pattern
    • Variation: "Shallow" extraction - Existing functionality will be exposed to MS
    • Use HTTP proxy to redirect calls
  • Migration patterns: UI composition
    • Example: Modules are migrated to MFEs one at a time; For mobile app: configs and layout of UI components is defined in declarative fashion on server side, so UI can be changed without new release
  • Migration patterns: Branch by Abstraction
    • Useful when: functionality to extract is deep inside existing system i.e. strangler fig is not suitable, or when changes will take a long tim. Using long-lived branches with new functionality getting developed is an option but not optimal. Branch by Abstraction will be a better option.
    • Try to use strangler fig pattern before considering this one
    • Steps:
        1. Create an abstraction for the functionality to be replaced
        1. Change existing client to use the abstraction
        1. Create new implementation using the abstraction. New impl. can be microservice etc/
        1. Switch abstraction to use new implementation e.g. use feature flags
        1. Clean up old code and optionally abstraction
        1. Fallback: if new implementation fails, switch back to old impl.
  • Migration pattern: Parallel Run
    • Both new + old impl. will be called, but only one (typically old impl.) will be considered source of truth.
    • Useful for verifying functional and non-functional parameters of new impl. especially for high risk areas
    • End goal isn't to replace the implmentations, but to reduce bugs in one of the impls.
    • Spy tools can be used to intercept/stub functionality e.g. verify email should be sent without actually sending
    • Parallel run isn't canary release, which redirect some users to new functionality.
    • Parallel run is a way to implement dark launching (function released but invisible)
    • Parallel run, canary releasing, dark launching all work to support progressive delivery

System Design Fundamentals - Juval Lowy (2023 H1)


1 What not to do

  • Avoid functional decomposition, or domain decomposition
  • Avoid bloating clients/thin service

2 What to do

  • Decompose based on volatility
  • Each areas of change is encapsulated (in a vault) - each represents an area of volatility
  • No block if no volatility

3 Using layers

  • Ask:
    • are volatilities in software system?
    • any interaction between areas of volatility?
  • layers imply top-down. Each layer is also an encapsulation. Within a layer are services (entities)
  • layers (top to bottom):
    • client layer (user/another system/techs) - volatility in client technology. Try to equalize all clients -- single point of entry to system
    • business layer - volatility in changes of system behavior. Good requirement is always behavioral (leave less room for interpretation) not functional i.e. use case/sequence of activities.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment