More on this book
Community
Kindle Notes & Highlights
Affinity might be caused because a group of functions perform a similar operation.
As in newspaper articles, we expect the most important concepts to come first, and we expect them to be expressed with the least amount of polluting detail.
We use horizontal white space to associate things that are strongly related and disassociate things that are more weakly related.
A source file is a hierarchy rather like an outline.
A team of developers should agree upon a single formatting style, and then every member of that team should use that style.
And yet the interface still unmistakably represents a data structure.
But it represents more than just a data structure.
Hiding implementation is not just a matter of putting a layer of functions between the variables.
A class does not simply push its variables out through getters and setters.
Rather it exposes abstract interfaces that allow its users to manipulate the essence of the data, without hav...
This highlight has been truncated due to consecutive passage length restrictions.
We do not want to expose the details of our data. Rather we want to express our data in abstract terms.
Serious thought needs to be put into the best way to represent the data that an object contains. The worst option is to blithely add getters and setters.
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 shape classes are simple data structures without any behavior.
Consider what would happen if a perimeter() function were added to Geometry.
On the other hand, if I add a new shape, I must change all the functions in Geometry to deal with it.
So if I add a new shape, none of the existing functions are affected, but if I add a new function all of the shapes must be changed!1
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures.
OO code, on the other hand, makes it easy to add new classes without changing existing functions.
Procedural code makes it hard to add new data structures because all the functions must change.
OO code makes it hard to add new functions because all the classes must change.
So, the things that are hard for OO are easy for procedures, and the things that are hard for...
This highlight has been truncated due to consecutive passage length restrictions.
In any complex system there are going to be times when we want to add new data types ...
This highlight has been truncated due to consecutive passage length restrictions.
For these cases objects and OO are mos...
This highlight has been truncated due to consecutive passage length restrictions.
On the other hand, there will also be times when we’ll want to add new functions ...
This highlight has been truncated due to consecutive passage length restrictions.
In that case procedural code and data structures will be...
This highlight has been truncated due to consecutive passage length restrictions.
There is a well-known heuristic called the Law of Demeter2 that says a module should not know about the innards of the objects it manipulates.
More precisely, the Law of Demeter says that a method f of a class C should only call the methods of these:
C
An object crea...
This highlight has been truncated due to consecutive passage length restrictions.
An object passed as an ar...
This highlight has been truncated due to consecutive passage length restrictions.
An object held in an instance v...
This highlight has been truncated due to consecutive passage length restrictions.
The method should not invoke methods on objects that are returned by any of...
This highlight has been truncated due to consecutive passage length restrictions.
In other words, talk to friends, not ...
This highlight has been truncated due to consecutive passage length restrictions.
The following code3 appears to violate the Law of Demeter (among other things) because it calls the getScratchDir() function on the return value of getOptions() and then calls getAbso...
This highlight has been truncated due to consecutive passage length restrictions.
This kind of code is often called a train wreck because it look like a bunch of coupled train cars.
Whether this is a violation of Demeter depends on whether or not ctxt, Options, and ScratchDir are objects or data structures.
If they are objects, then their internal structure should be hidden rather than exposed, and so knowledge of their innards is a clear violation of the Law of Demeter.
On the other hand, if ctxt, Options, and ScratchDir are just data structures with no behavior, then they naturally expose their internal st...
This highlight has been truncated due to consecutive passage length restrictions.
This issue would be a lot less confusing if data structures simply had public variables and no functions, whereas objects had private variables and public functions.
However, there are frameworks and standards (e.g., “beans”) that demand that even simple data structures have accessors and mutators.
Such hybrids make it hard to add new functions but also make it hard to add new data structures.
What if ctxt, options, and scratchDir are objects with real behavior?
Then, because objects are supposed to hide their internal structure, we should not be able to navigate through them.
If ctxt is an object, we should be telling it to do something; we should not be asking it about its internals.
Ignoring that, however, we see that the intent of getting the absolute path of the scratch directory was to create a scratch file of a given name.
So, what if we told the ctxt object to do this?
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
The quintessential form of a data structure is a class with public variables and no functions.