Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

SOLID Is Dead, Long Live SOLID

SOLID Is Dead, Long Live SOLID

Lemi Orhan Ergin

November 26, 2023
Tweet

More Decks by Lemi Orhan Ergin

Other Decks in Technology

Transcript

  1. SOLID DEAD IS SOLID LONG LIVE LEMİ ORHAN ERGİN co-founder,

    craftgate THE NEW PERSPECTIVE THE OLD LEGACY
  2. I know SOLID principles Really? How you apply? S for

    Single responsibility. I forgot the others. Of course we know SOLID. We think we use it all the time while coding and during code reviews. And of course it is a good thing. I've never heard the opposite. EVERYONE KNOWS SOLID PRINCIPLES, KNOWS THEM WELL!
  3. Preexisting knowledge impedes one’s ability to reach an optimal solution

    Every a tt empt referring to past solutions adds a new bracket to the wall of illusion of competence Agile, Devops, Clean Coding, SOLID, else? THE EINSTELLUNG EFFECT means mindset, attitude you past experience gives strong opinion about what it really is WE ALREADY KNOW IT, WHY BOTHERS? you never doubt the truth of what you know
  4. UNLEARN forget what you already know try to look from

    other perspectives re-learn from different views WHAT IF ALL WE KNOW IS WRONG, OR INCOMPLETE, OR MISSING years can change how things look, like how paintings change. real mona lisa seems different, isn’t it ?
  5. Payment API after a payment are completed, we save the

    data to database every design starts with the simpliest solution IMPLEMENT PAYMENT OPERATIONS 1 Save payment Retrieve payment GROWS SOFTWARE HOW DB
  6. Payment API We need to search existing payments FEATURE REQUEST

    where do we need to add the search operation ? It is a payment operation, so add it to same service ? Save payment Retrieve payment DB
  7. Payment API it’s a simple as querying the database with

    a search criteria and returning the results we add it to payment component as a new responsibility, a new flow 2 ADD SEARCH TO EXISTING FLOW Save payment Retrieve payment Search payment start with the simplest solution DB
  8. Payment API Search service requires additional models, introduces new dependencies

    and differentiates from core payment flow payment service starts to be huge and unmaintainable (new dependencies for search operation are not used and relevant with core payment flow) search flow has different business needs and triggered by different roles a change in the repository for search improvements directly triggers change in core payment flow Save payment Retrieve payment Search payment DB
  9. Payment API separate the search db operation from other db

    operations SPLIT INTO BOUNDED CONTEXTS 3 Save payment Retrieve payment Search payment two bounded contexts DB
  10. Search results are expected to be returned as files in

    csv and excel formats FEATURE REQUEST Payment API Save payment Retrieve payment Search payment DB
  11. Payment API generate report simply searches the data and fills

    it in a file with the given extension ADD NEW FLOW TO SEARCH MODULE 4 Save payment Retrieve payment Search payment Generate report we put generate report to the context of search DB
  12. Payment API Improvements in report generation triggers deployments on search,

    which is used excessively deploying the whole api is required whenever something added to report logic, that increases the risc on payment Save payment Retrieve payment Search payment Generate report DB the user of report generation is different than the users of payment and search operations
  13. Payment API Report API it’s time to introduce a new

    reporting api with generate report capabilities MOVE TO A NEW MICRO SERVICE 5 Save payment Retrieve payment Generate report Search payment DB
  14. Report generation takes time and users wait too long, timeout

    errors start to occur Payment API Report API things go even worse when multiple users trigger reports at the same time Save payment Retrieve payment Generate report Search payment DB
  15. Payment API Report API QUEUE each demand is queued, the

    throttlling logic can be managed Save payment Retrieve payment Generate report Search payment Demand report QUEUE DEMANDS AND PROCESS 6 two bounded contexts DB
  16. Payment API Report API QUEUE Report generation affects performance of

    search operations since the data source is shared, the load of reporting api has direct impact on payment operations Generate report Demand report Save payment Retrieve payment Search payment DB
  17. Payment API Report API QUEUE ELASTIC separate the read model

    of report generation from the model of payment operations Generate report Demand report Save payment Retrieve payment Search payment SEPARATE THE DATASOURCE 7 DB
  18. Payment API Report API ELASTIC Inform the user when the

    report is generated FEATURE REQUEST Save payment Retrieve payment Search payment QUEUE Generate report Demand report Report API DB
  19. Payment API ELASTIC Notification API email notification api directly sends

    emails and slack messages that provided by the report api INTRODUCE NOTIFICATION SERVICE 8 Save payment Retrieve payment Search payment Report API QUEUE Generate report Demand report Report API Send Slack message Send email DB
  20. Payment API ELASTIC Notification API email Report needs to know

    notification api and how to trigger its functionalities If notification api stops working, we lose messages Save payment Retrieve payment Search payment Report API QUEUE Generate report Demand report Report API Send Slack message Send email DB
  21. Payment API ELASTIC email QUEUE keep messages in queue and

    manage the error logic with retries QUEUE NOTIFICATION MESSAGES 9 Save payment Retrieve payment Search payment Report API QUEUE Generate report Demand report Report API Notification API Send Slack message Send email DB
  22. Payment API ELASTIC email QUEUE Whenever queue stops responding, the

    whole flow stops and messages are lost we lose messages when the queue is down :( Save payment Retrieve payment Search payment Report API QUEUE Generate report Demand report Report API Notification API Send Slack message Send email we lose demands when the queue is down :( DB
  23. Payment API ELASTIC email Outbox Inbox make messaging transactional and

    be sure you create messages MAKE MESSAGING TRANSACTIONAL 10 Save payment Retrieve payment Search payment Report API Generate report Demand report Report API Notification API Send Slack message Send email Generate report Send notification DB
  24. Payment API ELASTIC email Outbox Inbox We design a kind-a

    maintainable, expandable, robust system at the end make messaging transactional and be sure you create messages Save payment Retrieve payment Search payment Report API Generate report Demand report Report API Notification API Send Slack message Send email DB Generate report Send notification
  25. Extract to method, to classes, to functions Centralize decision making

    (behavior) Make responsible of one behavior Apply design patters Clearify boundaries of contexts Extract functionality as a new microservice Seperate by behaviors, not models or packages Avoid layered arc, build with hexagonal arch Avoid wrappers around CRUD operations Do not depend on same datasource Avoid distributed monoliths Avoid centralized common modules Do not depend on implementations Let the control of flow inverted (IoC) Prefer duplication to make independent Introduce abstrations to eliminate down times WE MANAGED COMPLEXITY BY DECREASING COUPLING AND INCREASING COHESION WHILE REFACTORING AND ADDING NEW CODE
  26. COUPLING In highly coupled systems, one change triggers a change

    in somewhere else The measure of the strength of interconnection, measure of independence If one system waits, changes, works, fails, starts, stops due to another systems action, these systems are highly coupled with the butterfly effect, every change thiggers something bigger Controller Service Service Service Repository Repository Utility Rest Client
  27. COHESION The code that changes together (i.e. in the same

    feature), stays together (only coupled to each other) Belonging together, relatedness, sharing same purpose/responsibility Cohesiveness exists inside boundaries, that makes it a module, a component, an element, a team, an organization
  28. Coupling & Cohesion perfectly fit to many other levels of

    abstractions of the world ONE TEAM TEAM A TEAM B when do we decide to split a team / an api / a module into two ? like team topologies
  29. Solid is not about good or simple design, it's about

    be tt er design. Solid is not about understanding OOP be tt er, it is about understanding the code (i.e. the design) be tt er. Solid is not the goal, it is a guideline for evaluating the way you refactor so ft ware into a be tt er design. IS NOT ABOUT... SOLID
  30. IS ABOUT MANAGING COMPLEXITY BY TAKING THE CONTROL OF COST

    BY COUPLING & COHESION SOLID SOLID is about limiting the impact of change by making easy to change the cost of change is the cost of software the impact of dependencies on easiness of change CODE PLANS PRIORITIES DECISIONS TEAMS APIS/SERVICES INFRASTRUCTURE
  31. is it about not writing too much code in one

    place ? SINGLE RESPONSIBILITY PRINCIPLE SRP
  32. SINGLE RESPONSIBILITY PRINCIPLE A class should only have a one

    single responsibility. There should never be more than one reason to change. A component should do only one thing, and do it right. This principle is about people. WHAT WE HAVE LEARNED SO FAR SRP
  33. SINGLE RESPONSIBILITY PRINCIPLE what is responsibility ? from what perspective

    ? many small classes ? you mean "high cohesion" ? what about fixing bugs and adding features ? what about cross cutting concerns ? converters ? facades ? patterns ? that's not always true A class should only have a one single responsibility. There should never be more than one reason to change. A component should do only one thing, and do it right. This principle is about people. multi layered architecture is not about SRP Programmers stated that needs clarifications WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED SRP
  34. SEPARATED CONCERN PRINCIPLE SRP is all about separation of concerns

    & contexts and increasing cohesion in an optimum level. A component should belong to one concern based on business responsibilities. Without context, every module can violate SPR to some extend. There is no such a thing as "do one thing” or “single”. There exists di ff erent levels of abstractions. It triggers how we split things into pieces. PRODUCT TEAMS FINE-GRAINED TASKS TEAM TOPOLOGIES BOUNDED CONTEXTS ENCAPSULATION INFIRMATION HIDING COGNITIVE FIT AGGREGATES MICROSERVICES SINGLE RESPONSIBILITY PRINCIPLE SRP keep cohesion as high as possible
  35. is it about small interfaces on top of huge codebase

    ? INTERFACE SEGREGATION PRINCIPLE ISP
  36. Clients should not be forced to depend on methods they

    do not use. Many client specific interfaces are be tt er than one general purpose interface. Interfaces should be small. INTERFACE SEGREGATION PRINCIPLE ISP WHAT WE HAVE LEARNED SO FAR
  37. Clients should not be forced to depend on methods they

    do not use. Many client specific interfaces are be tt er than one general purpose interface. Interfaces should be small. Programmers stated that needs clarifications is having interfaces a must ? should every class have an interface ? interface soup ? single method interfaces ? then aggregate again ? INTERFACE SEGREGATION PRINCIPLE WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED ISP WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED
  38. Limit coupling surface, minimize number of methods in the contract,

    limiting points to communicate. Keep abstractions highly cohesive so that users don’t end up depending on things they don’t need. Avoid depending on things that you do not use. INTERFACE SEGREGATION PRINCIPLE GATEWAY INFO HIDING ISOLATION COMPOSITION LIMITED CONTACT SURFACE PRINCIPLE ISP LIMIT DEPENDENCIES RICH DOMAIN MODEL lower the number the touching points of coupling
  39. LISKOV SUBSTITUTION PRINCIPLE LSP If an object y has all

    the properties of object x, then we can safely use y anywhere we use x and that y is a subtype of x. If y does not have all the properties of x, it is not a subtype of x. Every derived class should be substitutable for their base class. WHAT WE HAVE LEARNED SO FAR
  40. If an object y has all the properties of object

    x, then we can safely use y anywhere we use x and that y is a subtype of x. If y does not have all the properties of x, it is not a subtype of x. Every derived class should be substitutable for their base class. isn't it all OOP related ? what if we do not use subtypes at all ? Programmers stated that needs clarifications LISKOV SUBSTITUTION PRINCIPLE LSP is inheritance a must ? WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED
  41. A class/module/team should do what it sounds like it does.

    Any behavioral change breaking this that should be a di ff erent dependency. LSP is not about inheritance, it is about behaviour of code units. Build so ft ware systems from interchangeable parts, those parts must adhere to a contract that allows those parts to be substituted one for another. LISKOV SUBSTITUTION PRINCIPLE LSP GATEWAY INFO HIDING ISOLATION COMPOSITION TEST DOUBLES INTER-CHANGEABLE DEPENDENCIES PRINCIPLE prefer un-fixed dependencies
  42. DEPENDENCY INVERSION PRINCIPLE DIP High-level modules should not depend on

    low-level modules. from code that is stable separate code that changes frequently business code domain logic integration code client specific code framework dependent code delay technological decisions immune to technical evolution test domain in isolation knows about needs WHAT WE HAVE LEARNED SO FAR
  43. DEPENDENCY INVERSION PRINCIPLE DIP Abstractions should not depend on details.

    Details should depend on abstractions. interfaces ports implementations adapters the depending class has no knowledge about the concrete class that it is going to use WHAT WE HAVE LEARNED SO FAR
  44. DEPENDENCY INVERSION PRINCIPLE DIP High-level modules should not depend on

    low-level modules. Abstractions should not depend on details Details should depend on abstractions. WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED Programmers stated that needs clarifications where is the inversion ? isn’t it too abstract ? concrete classes are depent on interfaces in nature, so what ?
  45. DIP is about making the business independent of external systems

    by making coupling cheap and so ft . Decouple your behavioral models from your data models. DIP decouples the construction of an object from its use. DEPENDENCY INVERSION PRINCIPLE DIP PORTS & ADAPTERS HOLLYWOOD PRINCIPLE EVENT DRIVEN DESIGN INVERSION OF CONTROL SELF ORGANIZATION MODULAR DESIGN PLUGINS & ADD-ONS soften the impact of coupling and improve cohesiveness DECOUPLED DEPENDENCIES PRINCIPLE
  46. OPEN CLOSED PRINCIPLE OCP So ft ware entities should be

    open for extension, but closed for modification. Developers must support new functionality without editing the source code of the existing modules. The source code of such a [class] is inviolate. No one is allowed to make source code changes to it. You can use interfaces as extension points to make your code truly adaptable. WHAT WE HAVE LEARNED SO FAR
  47. OPEN CLOSED PRINCIPLE OCP So ft ware entities should be

    open for extension, but closed for modification. Developers must support new functionality without editing the source code of the existing modules. The source code of such a [class] is inviolate. No one is allowed to make source code changes to it. You can use interfaces as extension points to make your code truly adaptable. Programmers stated that needs clarifications source code can’t be changed ? who can write perfect code ? abuse of inheritance ? change requires refactoring WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED WHAT WE HAVE LEARNED SO FAR SHOULD BE CHALLENGED
  48. Expose potential extension points. For protection against change to the

    existing code, identify points of evolution points, create a stable interface around them. We need just enough adaptability. You should be explicit in what you allow and disallow to be extended. PROTECTED VARIATION PRINCIPLE ROOT OF ALL PATTERNS OPEN CLOSED PRINCIPLE OCP information hiding, PV and OCP are all same principle with a different name and view PROTECTED VARIATION PRINCIPLE manage the growth of codebase by adding coupling in control EVOLUTIONARY DESIGN TEAM STANDARDS CONTINUOUS REFACTORING CONWAY’S LAW
  49. SRP Separated Concerns keep cohesion as high as possible ISP

    Limited Contact Surface lower the number the touching points of coupling prefer un-fixed dependencies Interchangeable Dependencies LSP DIP manage the growth of codebase by adding coupling in control Decoupled Dependencies OCP Protected Variation so ft en the impact of coupling and improve cohesiveness Cohesion Coupling SOLID PRINCIPLES