• Home
  • Quick Bytes
  • Algorithms
  • Java
  • iOS
  • Android
  • Certifications
  • About Me

Lets Code Them Up!

  • Clean Architecture – Chapter 14 | Component Coupling | The Acyclic Dependency Principle

    May 13th, 2023

    So far we have gone through defining component and understanding what makes a component in previous chapters. In this post we start looking into principle that talk about the relationships between component. Let’s start with the acyclic dependency principle.

     

    Allow no cycles in the component dependency graph

    Robert Martin

    A very common scenario that we developers face – We are working on a project, make some code changes, verify it’s working, so log out for day/commit the changes. Next day or few days later, we find that our integration tests are failing! Root cause comes out to be a change in one of our dependencies. This leads to either reverting our change or working on fix. The author calls this “morning after syndrome”.

    Solution to this problem of running into frequent changes caused by changes in dependencies – The Weekly Build

    The Weekly Build

    As per this, developers work for 4 days in a week on their code and on fifth day they integrate their changes and build the system. 

    Now this could work when the team is small/the system is small so there are fewer teams. But when the system would grow, components and teams owning those components would grow. Eventually we would find that it takes more time to integrate and so pushing the integration days one day back. Ultimately a build per week won’t be sufficient and we would starting doing a build every two weeks. This could increase to month!

    Clearly this solution cannot work for large systems. 

    Dependency Cycles elimination

    The solution is to partition the development environment into releasable components. Each component could have its release versions with each change. The components consuming these changed components can then decide to move to new version or keep using the previous ones. This reduces the dependencies between teams and they can work independently. 

    The key for this approach to work is – When components depend on other components, there should be no cycles.

    Say we have three components A, B, C. A depends on B, B depends on C. There will be a cycle if C would depend on A. If there is no cycle, any changes in A would force changes in B and C. Any change in B would only force C to change, A is safe. Any change in C would not force any change in A or B.

    However if there is a cycle, then any change in A, B or C would need changes in all components. 

    So if there are cycles in the way our component depends on each other, we need to break it – 

    1. Use DIP (Dependency Inversion Principle), invert dependency by using interfaces. 
    2. Add the common classes between two components to a third component and then depend on that component.

    Top Down Design

    When we start building the system, we could be grouping classes based on usability. Few iterations later, we might worry about reusability of components and start moving around classes by creating new components and new dependencies between them. We can see the component structure keeps on evolving based on the requirements at each stage of our development. And so we cannot design this structure at the beginning in top down manner. 

    Thanks for stopping by! I hope this gives a good preview into acyclic dependency principle. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

  • Clean Architecture – Chapter 13 | Component Cohesion

    May 6th, 2023

    In our previous post, we went through what a component is? Next question that comes is – Which classes go in which component? This chapter defines three principles to keep into mind while grouping classes into components – 

    1. REP: The Reuse/Release Equivalence Principle
    2. CCP: The Common Closure Principle
    3. CRP: The Common Reuse Principle

    The Reuse/Release Equivalence Principle

    The granule of reuse is the granule of release.

    Robert Martin

    All of us are familiar with module management softwares like maven, gradle, etc. These software helps us reuse classes from other dependencies in our projects. We have seen that every module that is part of these systems comes with a release process and release numbers. 

    The release numbers and the release documentation helps the consumer in deciding whether to move to new version or remain on an old one. 

    REP, on architectural level means that classes which form a component must belong to a cohesive group. They should not be a random group of classes, but should have some theme/purpose which they all share. In other words, classes in a component should be releasable together. 

    What would be the outcome if we group random classes together? The consumers would know about it, they would know that they depend on our package and it has classes which don’t make any sense to be in our package. They would know that any change in those classes would also unnecessary force them to change. This would show our weak architectural skills.

    This principle, although very important, gives a weak advice. It says similar classes should be grouped together, but, doesn’t have a strong criteria that architects can follow. The weakness of this principle is compensated by the other two principles. 

    The Common Closure Principle

    Gather into components those classes that change for the same reasons at the same time. Separate into different components those classes that change at different times and for different reasons.

    Robert Martin

    This is similar to Single Responsibility Principle. SRP stated to keep methods that change for different reasons in separate classes. CCP states to keep classes that change for different reasons in separate components. 

    Following this principle ensures that if something needs to change then only one component is affected as it has all classes related to that change. We would need to only redploy that component. The other components who depend on that component would not change. 

    This principle is also similar to Open Closed Principle. OCP states that classes should be closed for modification, but open for extension. CCP augments this principle by keeping the classes which are closed to same type of changes together in one component. So, if change comes in requirements, only few components change.

    The Common Reuse Principle

    Don’t force users of a component to depend on things they don’t need.

    Robert Martin

    This principle keeps the classes that can be reused together into same component. 

    When component uses even one class from another component, a dependency is created between them. If the used component has other classes which the using component doesn’t depend on. Then any change in those classes would force using component to have changes as well. 

    So, when we depend on a component we need to be sure we are using all the classes in that component. It means, we want to keep together the classes that are inseparable (impossible to depend on one and not on others) in to one component.

    Tension diagram for component cohesion

     

    The above diagram shows the tension diagram for component cohesion. The edges of the diagram define the cost of abandoning principle on the opposite vertex.

    If an architect focuses on REP and CRP then he will find too many components which change when a new requirement comes. If an architect focuses on CRP and CCP, then he will find he has too many components which are hard to reuse. If an architect focuses on REP and CCP then he will find he has components which have very frequent releases. 

    A good architect will need to find a position in the triangle which meets the concerns of the current development team, but would also be aware that those concerns will change over time. 

    For example, when I started working recently on a new project which is rearchitecting current system, our focus initially has been on CCP. We have many components which have classes that change together. At the same time, we have many classes which are reusable together, but currently they are in different components. But as the project matures, things have been changing and we are moving more towards REP. 

    In conclusion, we need to start grouping classes together into components, we must consider opposing forces involved in reusability and develop-ability. And also acknowledge, that partitioning that is relevant today might not be relevant in future, but would keep on evolving. 

    Thanks for stopping by! I hope this gives a good preview into component cohesion. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

  • Clean Architecture – Chapter 12 | Components

    April 29th, 2023

    Components are smallest units of deployment. In java, they are jar files. In ruby, they are gem files and so on. 

    This chapter mainly focuses on history of components, how they came into existence in the software world. 

    Starting from the earliest – 

    1. At first, programmers used to write their programs starting the the physical address where they would be stored in memory. Programs were not relocatable. Programmers would include the source code of library functions with the application code. This resulted in longer load time if programs were big. And eventually this approach failed for very big programs. 
    2. Relocatable binaries came next to solve this problem. Compiler was changed to output binaries which included function names as metadata. These binaries also, included the address to be loaded and other flags. All this information was then given to loader. Loader would link the function names to place where it has loaded them. Now, programmers can load only the required functions using loader
    3. The above approach worked well for small systems. As the number of libraries increase, the time taken by these linking loaders increased. And so linking and loading were separated. Programmers put the linking part into linker. The output of linker was link relocatable file that a relocating loader can quickly load. But still the loading time couldn’t be reduced. 
    4. As storage optimized, disk became short and fast, RAM became fast and efficient, time spent linking and loading application began to shrink too fast. Next came .jar files, and applications where multiple .jar files can be loaded and linked in few seconds. This was era of component plugin architecture. Here, say you want to pin photos on google chrome, just create an extension/plugin and add it to chrome and have it working. 

    These dynamically linked files are called the components of our architecture.

    Thanks for stopping by! I hope this gives a good preview into components. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

  • Clean Architecture – Chapter 11 | DIP | Dependency Inversion Principle

    April 22nd, 2023

    So far we have gone through Single Responsibility Principle, Open Closed Principle , Liskov Substitution Principle, Interface Segregation Principle which cover four SOLID principles. In this post, we will go through D ie Dependency Inversion Principle.

    DIP says that the most stable systems are those in which source code dependencies refer to abstractions and not to concretions.

    Dependency inversion principle cannot be followed as rule because in reality we have to depend on concrete implementations like operating systems, platforms, String in Java, etc. The dependencies like these which are stable and very unlikely to change are excluded from this principle. 

    The dependencies that are volatile, that are still developing, that can change, we should be depending on their interfaces and not on concrete implementations. 

    Stable Abstractions

    Stable architectures are those that avoid depending on volatile concretions and that favor the use of stable abstract interfaces. They follow following rules – 

    1. Don’t refer to volatile concrete classes
    2. Don’t derive from volatile concrete classes
    3. Don’t override concrete functions – concrete functions have dependencies, when you override them, you inherit these dependencies. So ideally we should make functions abstract and create multiple functions.
    4. Never mention the name of anything concrete and volatile

    Thanks for stopping by! I hope this gives a good preview into DIP. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

  • Clean Architecture – Chapter 10 | ISP | Interface Segregation Principle

    April 15th, 2023

    So far we have gone through Single Responsibility Principle and Open Closed Principle , Liskov Substitution Principle, which cover three SOLID principles. In this post, we will go through I ie Interface Segregation Principle. 

    Let’s go through an example to understand this principle. 

    Let’s say OPS class has three operations op1, op2, and op3. And there are three users, User1 uses op1, User2 uses op2, User3 uses op3 . If there is change in op3, both User1 and User2 will have to recompile and redeploy their code. 

    Now instead if each of these operations are segregated into three different interfaces and each user just depends on their interface, then if there is change in op3, only user3 will need to recompile and redeploy their code. This is called Interface Segregation Principle. 

     

    ISP and Languages

    In statically typed languages like Java, with statements like import, include, use, etc, create source code dependencies, that force recompilation and redeployment and so ISP becomes necessary.

    In dynamically typed languages, where declarations does not exists, but inferred at runtime, there are no source code dependencies, that force recompilation and redeployment. This is primary reason systems with dynamically typed languages are more flexible and less tightly coupled.

    ISP and Architecture

    ISP is just not language level restriction. But it is also relevant at architecture level. It is harmful to depend on a module that contains more than you need. 

    For example, you are architecting a system, and you decide to use a framework that depends on a database. If there is change in the database, both the framework and your system would need to recompile and redeploy. Or if any feature in the database fails, it will call failure in both the framework and your system. 

    The lesson is depending on something that carries extra baggage that we don’t need can cause us trouble that we don’t expect.

    Thanks for stopping by! I hope this gives a good preview into ISP. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

     

  • Clean Architecture – Chapter 9 | LSP | The Liskov Substitution Principle

    April 9th, 2023

    So far we have gone through Single Responsibility Principle and Open Closed Principle , which cover two SOLID principles. In this post, we will go through L ie Liskov Substitution principle. 

    If for each object o1 if type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

    Barbara Liskov

    LSP originated as a way to guide use of Inheritence. 

    Let’s look at an example where an implementation of inheritence violates LSP.

    Consider the Square/Rectangle problem. Here Square is not a proper substitute of Rectangle as height and width of rectangle are different from that of Square. For Rectangle, user needs to set width and height, but for Square, one has to set only side. And as Square is subtype of rectangle, it inherits both height and width of Rectangle. And if user wants to calculate area of square, he could easily set width and height as different resulting in wrong area/perimeter of square. And so developer would need to add special implementation to make sure to check if given instance of Rectangle is a Square.

    LSP and Architecture

    Let’s look at the example given in the book of taxi aggregator service that aggregates many taxi dispatch service. Customer uses this service to find the best taxi for them regardless of the taxi company. Once the customer selects the driver, the service dispatches the chosen taxi.

    Let’s say the URI the service uses is part of the information contained within driver database. Suppose customer chooses Bob’s taxi, then our service dispatches the request to Bob using the URI stored for him in the data base

    example – assuming dispatch uri for BOB is 24hrTaxi.com/driver/Bob, so the PUT request to Bob will be like 24hrTaxi.com/driver/Bob/pickupAddress/1234 happy st./pickupTime/1430/destination/LAX

    All taxi services will need to conform to this interface to be able to interface with the aggregator service. Let’s say TaxiAnyTime.com, changes he interface and uses dest instead of destination. This is violating LSP, as all services are not conforming to one interface. And so we will need special logic in our dispatcher service to handle different parameters for this taxi service.

    So LSP should be followed at architecture level as a simple violation of LSP can cause additional code/mechanisms to be put in the architecture as fallbacks.

    Thanks for stopping by! I hope this gives a good preview into LSP. Eager to hear your thoughts and chat, please leave comments below and we can discuss. 

     

     

←Previous Page
1 … 4 5 6 7 8 … 22
Next Page→

Proudly powered by WordPress

 

Loading Comments...