Notes on Clean Code — Ch.6 Objects and Data structures

Shun Yao
shunys tech adventure
3 min readAug 1, 2018

This is my notes on reading Clean Code by Robert C. Martin.

https://www.valuecoders.com/blog/technology-and-apps/programming-trends-2017-it-outsourcing-companies/

Conclusion of the Chapter

This chapter talks about objects and data structures.

Objects expose behavior and hide data.

  • Easy to add new kinds of objects without changing existing behaviors.
  • Difficult to add new behaviors to existing objects

Data structures expose data and have no significant behavior.

  • Easy to add new behaviors to existing data structures
  • Difficult to add new data structures to existing functions

Good engineers need to choose Object of Data structure depending on scenario.

Data/Object Anti-Symmetry

This section is about choosing OO vs Procedure code.

Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions

The author gives an example of using Shape classes (Rectangle, Square, Circle) and Geometry class that performs operations on the Shape classes. Geometry class has function, area(Object shape) and do if conditions on the shape to calculate the area for different classes. This seemingly is against Object oriented, but it is easy to add methods to Geometry class without altering other classes. Say if you want to add perimeter(Object shape) method to Geometry, you can add without changing anything else. However, if you want to add a new shape, all functions in Geometry class need to be modified.

On the contrary, if area() function is in each of the Shape class, it is easy to add new Shape class. However, if new function is added, all Shape class needs to be modified.

Procedure code (code using data structures): Easy to add new functions without changing the existing data structures. Hard to add new data structures because all of the functions must change.

OO code: Easy to add new classes without changing existing functions. Hard to add new functions because all the classes must change.

What I learned in this section

  1. There is a clear difference between Object and Data Structure. Object is not supposed to expose its internal structure. Its methods perform significant operations.
  2. Data Structure should not have significant methods. It exposes its internal structures.

The Law of Demeter

Module should not know about the innards of the objects it manipulates. Method should not invoke methods on objects that are returned by any of the allowed functions.

A method f of a class C should only call the methods of

  • C
  • An object created by f
  • an object passed as an argument to f
  • an object held in an instance variable of C.

The example given is

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

This is called Train Wrecks because it looks like a bunch of coupled train cars. This should be avoided and best split into

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();

This seems a violation of Law of Demeter. If opts, scratchDir, and outputDir are data structures, rather than objects, that would be fine because they naturally expose their internal structure.

There is confusion of violation of Law of Demeter because of hybrids of objects and data structures. They have functions that do significant things and they also have public variables or public accessors and mutators that make the private variables public.

How to avoid this issue? The author first gives two failing modifications.

ctxt.getAbsolutePathOfScratchDirectoryOption();

This is bad because this could lead to explosion of methods in the ctxt object.

ctx.getScratchDirectoryOption().getAbsolutePath();

This is bad because getScratchDirectoryOption(0 returns a data structure, not an object.

The better approach is to understand why we need this method in first place. The motivation came from creating a scratch file of a given name. So, it would be better to just

BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName)

This hides ctxt internals and prevents the current function from having to violate the Law of Demeter by navigating through objects it shouldn’t know about.

What I learned in this section

  1. To fix data exposure, the first step is to understand the motivation for the method.
  2. A function should not need to have knowledge of the internal structures of the objects to perform an operation.

--

--