Message Chains

When code navigates a series of object interactions, it creates long, tightly coupled chains.

Sign of Smell

Message Chains, also known as Train Wrecks, occur when a client requests an object, which in turn requests another object, and so on. Navigating through a series of object interactions can result in long and tightly coupled chains. These chains indicate that the client depends heavily on traversing the class structure.

Long sequences of method calls indicate hidden dependencies as intermediaries. Similarly, using a sequence of temporary variables could also hide the sequence of methods. The issue with this problem is that any modification in the intermediate relationship requires the client to make changes as well.

However, there are situations where delegations become necessary, and delegation chains with a few links are generally considered to be harmless. The number of links that a chain can reasonably have is often dependent on other factors. For more guidance on designs with highly coupled chained delegations, consider the other design maxims mentioned below.

Notice that Message Chain and Middle Man are closely related and often one leads to the other.

Reason of Smell

Here's why Message Chains are problematic:

  • Tight Coupling: Message Chains create tight coupling between objects. In a chain of method calls like objectA.getObjectB().getObjectC().getValue(), each object depends directly on the next one in the chain. This tight coupling makes the code less flexible and more difficult to modify because changes in one part of the chain can have a ripple effect on other parts.

  • Violation of "Tell, Don't Ask": Message Chains often violate the "Tell, Don't Ask" principle. Instead of instructing objects to perform actions, the client object in the chain repeatedly queries other objects for data and makes decisions based on that data. This leads to a less object-oriented and more procedural style of code.

  • Violation of Law of Demeter: Message Chains often violate the Law of Demeter, also known as the "principle of least knowledge." This principle suggests that an object should have limited knowledge of the internal structure of other objects. In Message Chains, one object often has to know a lot about the structure of several other objects in the chain.

  • Reduced Encapsulation: Message Chains often require exposing internal details of objects to the caller. For example, if objectA needs to access methods from objectB, it may need to expose those methods publicly, violating the principle of encapsulation and hiding implementation details.

  • Brittleness: Any changes to the structure of the chain or the behavior of intermediate objects can break the chain. This brittleness makes the code less robust and more prone to errors.

  • Maintenance Challenges: When you have long chains of method calls, it becomes challenging to maintain and understand the code. Developers need to trace the entire chain to comprehend what's happening, and debugging can be cumbersome.

  • Reduced Testability: Testing becomes more challenging when there are message chains because isolating the behavior of a single object for testing purposes is difficult. Testing the entire chain may be necessary, making unit tests less focused and harder to maintain.

Refactoring Recipes

  • Hide Delegate

  • Extract Method

  • Move Method

Hide Delegate

It solves the Message Chains by encapsulating access from a long object or method chain within a delegating method or property. This hides the direct connection between classes, reducing interdependence and promoting better encapsulation.

However, it introduces a "Middle Man" between the two classes, which could potentially cause another code smell.

Extract Method

The “Extract Method” can solve the smell by encapsulating the chain of method calls within a single method. A Message Chain is nothing but a sequence of method calls on multiple objects, so we can replace it by creating a new method in the class that contains the Message Chain. This method will replace the entire chain and should return the desired result or perform the necessary action.

Move Method

When we come across a tightly coupled long method chain, one way to address this issue is by moving a method from one class to another, where it logically belongs. This helps to break the chain and improve code organization. This approach helps to reduce the interdependence between the classes.

Reference

https://luzkan.github.io/smells/message-chain

https://refactoring.guru/smells/message-chains

https://oowisdom.csse.canterbury.ac.nz/index.php/Message_chain_smell

https://stackoverflow.com/questions/6609296/message-chains-vs-middle-man

https://wiki.c2.com/?TrainWreck

Last updated