Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Modularization Strategies - Fixing Class and Package Tangles

75 views

Published on

When you have lots of tangles in your code, it results in a mess - it becomes unstructured. This simple presentation shows code examples and the visualization of the corresponding code in Structure101 Workspace to show how the code refactoring or package restructuring can be performed to fix the tangles. Limiting to three strategies to keep the examples simple and crisp.

Published in: Software
  • Be the first to comment

Modularization Strategies - Fixing Class and Package Tangles

  1. 1. MODULARIZING STRATEGIES: FIXING CLASS & PACKAGE TANGLES ganesh samarthyam (ganesh@codeops.tech)
  2. 2. WHAT’S A “TANGLE”? ➤ “A tangle is a portion of a dependency graph within which all the items are directly or indirectly dependent on all the other nodes in the tangle.” (Source: structure101.com) Example of a class tangle (cycle) Example of a package tangle
  3. 3. REMOVING TANGLES - VISUALISING IN STRUCTURE101
  4. 4. REFACTORING CLASS TANGLES
  5. 5. DEPENDENCIES BETWEEN CONCRETE CLASSES - TANGLE import java.util.List; public class Customer { List<Order> orders; } class Order { Customer purchaser; } A direct cyclic dependency between the Customer & Order class because they contain instances of each other’s type
  6. 6. DEPENDENCIES BETWEEN CONCRETE CLASSES - TANGLE - FIX import java.util.List; public class Customer { List<Order> orders; } class Order { Customer purchaser; } Depend on the interface instead of the implementation (and the cycle is gone) import java.util.List; interface Buyer {} public class Customer implements Buyer { List<Buyable> orders; } interface Buyable {} class Order implements Buyable { Buyer purchaser; }
  7. 7. BASE CLASS REFERS TO ITS DERIVED TYPES(S) enum ImageType { JPEG, BMP, PNG }; abstract class Image { public static Image getImage(ImageType imageType, String name) { switch (imageType) { // JPEGImage, BMPImage, PNGImage are // derived classes of the abstract class Image case JPEG: return new JPEGImage(name); case BMP: return new BMPImage(name); case PNG: return new PNGImage(name); } return null; } } This is a special kind of cyclic dependency - the base type knows about its derived type! Here it is creation of its derived objects results in a tangle
  8. 8. BASE CLASS REFERS TO ITS DERIVED TYPES(S) - FIX It’s easy to break this cyclic dependency - move the getImage() method to a dedicated class named ImageFactory!
  9. 9. AVOIDABLE REFERENCES TO CLASSES - TANGLE In this case, the Target abstract class has unnecessary references to concrete classes; instead of overloading, could be specific method calls instead package main; abstract class Target { public abstract void genCode(Constant constant); public abstract void genCode(Plus plus); public abstract void genCode(Mult mult); } class JVMTarget extends Target { public void genCode(Constant constant) { System.out.println("bipush " + constant.getValue()); } public void genCode(Plus plus) { System.out.println("iadd"); } public void genCode(Mult mult) { System.out.println("imul"); } } class DotNetTarget extends Target { public void genCode(Constant constant) { System.out.println("ldarg " + constant.getValue()); } public void genCode(Plus plus) { System.out.println("add"); } public void genCode(Mult mult) { System.out.println("mul"); } } abstract class ExprNode { protected static Target target = new JVMTarget(); public static void setTarget(Target newTarget) { target = newTarget; } public abstract void genCode(); } class Constant extends ExprNode { int val; public Constant(int arg) { val = arg; } public int getValue() { return val; } public void genCode() { target.genCode(this); } }
  10. 10. UNNECESSARY REFERENCES TO CLASSES - TANGLE - FIX abstract class Target { public abstract void genCodeConstant(int constValue); public abstract void genCodePlus(); public abstract void genCodeMult(); } class JVMTarget extends Target { public void genCodeConstant(int constValue) { System.out.println("bipush " + constValue); } public void genCodePlus() { System.out.println("iadd"); } public void genCodeMult() { System.out.println("imul"); } } abstract class Target { public abstract void genCode(Constant constant); public abstract void genCode(Plus plus); public abstract void genCode(Mult mult); } class JVMTarget extends Target { public void genCode(Constant constant) { System.out.println("bipush " + constant.getValue()); } public void genCode(Plus plus) { System.out.println("iadd"); } public void genCode(Mult mult) { System.out.println("imul"); } } By making the Target class not refer to the concrete ExprNode classes, the tangle is gone!
  11. 11. SUMMARY - STRATEGIES FOR BREAKING CLASS TANGLES Cause(s) Potential Solution(s) References among concrete classes causes cycle(s)/tangle(s) Depend on the interfaces than on the concrete classes (extract interfaces if they are absent) A base class refers to one or more of its derived class(es) causing tangle(s) (e.g., base class creates objects of its derived types) Remove the offending references from base class to the derived class(es) (e.g., move the object creation to a dedicated factory class) Unnecessary references to classes causes tangles Remove the unnecessary references
  12. 12. REFACTORING PACKAGE TANGLES
  13. 13. INTERFACE & IMPLEMENTATION PACKAGED TOGETHER Packaging the interface & corresponding implementation together causes tangle! package buyers; import buyables.Buyable; import java.util.List; interface Buyer {} public class Customer implements Buyer { List<Buyable> orders; } package buyables; interface Buyable {} public class Order implements Buyable { Buyer purchaser; }
  14. 14. INTERFACE & IMPLEMENTATION PACKAGED TOGETHER - FIX Separating the interfaces as a separate package (from the implementation package) disentangles the structure!
  15. 15. MISPLACED ENTITY - PACKAGE TANGLE An entity misplaced in a package causes a tangle (where does enum ImageType belong? In the “factory” package or “image” package? package image; import factory.ImageType; public abstract class Image { public abstract ImageType getType(); } package factory; public enum ImageType { JPEG, BMP, PNG } package imagetypes; import factory.ImageType; import image.Image; public class BMPImage extends Image { public BMPImage(String name) { super(); } public ImageType getType() { return ImageType.BMP; } }
  16. 16. MISPLACED ENTITY - PACKAGE TANGLE - FIX Here, the entity “enum ImageType” arguably belongs better in “image” package than in the “factory” package (moving the enum breaks the tangle)
  17. 17. MIXED PACKAGE - PACKAGE TANGLE Here, the Expr class and the builder class ExprBuilder (that builds objects) are put together in the same “core” package - this results in a tangle package core; import nodes.*; public class ExprBuilder { private Expr expr = null; public ExprBuilder() {} public ExprBuilder Const(int arg) { expr = Constant.make(arg); return this; } public ExprBuilder Plus(int arg) { expr = new Addition(expr, Constant.make(arg)); return this; } public ExprBuilder Mult(int arg) { expr = new Multiplication(expr, Constant.make(arg)); return this; } public Expr Build() { return expr; } }
  18. 18. MIXED PACKAGE - PACKAGE TANGLE - FIX The tangle is broken by splitting the 
 “core” package into two packages (“core” and “builder”)
  19. 19. SUMMARY - STRATEGIES FOR BREAKING PACKAGE TANGLES Cause(s) Potential Solution(s) Interfaces and implementations are mixed together Separate the interfaces and implementations to separate packages A class is misplaced in a package causing a tangle Move the offending class to a more suitable package Classes that may not belong together packaged into a single package cause a tangle Split the package
  20. 20. www.codeops.tech www.konfhub.com www.designsmells.com

×