Clean Code Made Simple - Part 3
Mehrad Sadeghi • August 15, 2022
Further to my last posts Part 1 and Part 2 of Clean Code Made Simple, in this post I'm going to continue introducing techniques from Robert C. Martin’s Clean Code book.
#11 Law of Demeter
As wikipedia says:
The Law of Demeter (LoD) or principle of least knowledge is a design guideline for developing software, particularly object-oriented programs. can be succinctly summarized in each of the following ways: 1. Each unit should have only limited knowledge about other units: only units "closely" related to the current unit. 2. Each unit should only talk to its friends; don't talk to strangers. 3. Only talk to your immediate friends.
Now that we have a basic understanding of Demeter's law, in order to prevent breaking it, which one of following structures do you think is better ?
$ctx->getAbsolutePathOfScratchDirectoryOption();
or
$ctx->getScratchDirectoryOption().getAbsolutePath()
well non is good. If ctx is an object, we should be telling it to do something; we should not be asking it about its internals.
Consider far from code about (in that module) we needed the outputDir
like below:
$outFile = $outputDir + "/" + $className->replace('.', '/') + ".class";
$fout = new FileOutputStream($outFile);
$bos = new BufferedOutputStream($fout);
So, what if we told the ctx object to do this:
$bos = $ctx->createScratchFileStream($classFileName);
That seems like a reasonable thing for an object to do! This allows ctx to hide its internals and prevents the current function from having to violate the Law of Demeter by navigating through objects it shouldn’t know about.
#12 Standard Pattern Names
By using the standard pattern names, such as COMMAND
or VISITOR
, in the names of the classes that implement those patterns, you can succinctly describe your design to other developers.
#13 Doing One Thing
How do you think we can figure out a function is doing more than “one thing” ?
The answer is that if you can extract another function from it with a name that is not merely a restatement of its implementation, Then you would know it's doing more than one thing.
To do so, we need to make sure that the statements within our function are all at the same level of abstraction. for example
getHtml()
is at a very high level of abstraction,
$pagePathName = PathParser::render($pagePath);
is at intermediate abstraction,
and something like ->append("\n")
is at low level of abstraction
#14 Base Class and Derivatives
The most common reason for partitioning concepts into base and derivative classes is so that the higher level base class concepts can be independent of the lower level derivative class concepts. Therefore, when we see base classes mentioning the names of their derivatives, we suspect a problem. In general, base classes should know nothing about their derivatives.
There are exceptions to this rule, of course. Sometimes the number of derivatives is strictly fixed, and the base class has code that selects between the derivatives. We see this a lot in finite state machine implementations. However, in that case the derivatives and base class are strongly coupled and always deploy together. In the general case we want to be able to deploy derivatives and bases separately.
#15 Naming
Methods should have verb or verb phrase names like postPayment, deletePage, or save. Accessors, mutators, and predicates should be named for their value and prefixed with get, set, and is.
$name = employee->getName();
$customer->setName("mike");
if ($paycheck->isPosted())...
Okay. This is it for this part. You can join my Telegram channel to get notified of the latest posts. Also, you can follow me on Twitter and LinkedIn.