visit
We want our code to behave different on different environments, operating systems, so taking decisions at compile time is the best decision, isn't it?.
#if VERBOSE >= 2
printf("trace message");
#endif
if (runtimeEnvironment->traceDebug()){
printf("trace message");
}
## even better with polymorphism and we avoid annoying ifs
runtimeEnvironment->traceDebug("trace message");
Bjarne Stroustrup, in his book The Design and Evolution of C++, regrets on the pre-processor directives he created years before.
C++ is designed to allow you to express ideas, but if you don't have ideas or don't have any clue about how to express them, C++ doesn't offer much help.
Bjarne Stroustrup
sort, sortOld, sort20210117, workingSort, It is great to have them all. Just in case
findMatch()
findMatch_new()
findMatch_newer()
findMatch_newest()
findMatch_version2()
findMatch_old()
findMatch_working()
findMatch_for_real()
findMatch_20200229()
findMatch_thisoneisnewer()
findMatch_themostnewestone()
findMatch_thisisit()
findMatch_thisisit_for_real()
findMatch()
That's why I write, because life never works except in retrospect. You can't control life, at least you can control your version.
Chuck Palahniuk
Searching for a concrete method implementation? Go back and forth, up and down.
TL;DR: Don't ab(use) hierarchies.
<?
abstract class Controller {
}
class BaseController extends Controller {
}
class SimpleController extends BaseController {
}
class ControllerBase extends SimpleController {
}
class LoggedController extends ControllerBase {
}
class RealController extends LoggedController {
}
<?
interface ControllerInterface {
}
abstract class Controller implements ControllerInterface {
}
final class LoggedControllerDecorator implements ControllerInterface {
}
final class RealController implements ControllerInterface {
}
An error arises from treating object variables (instance variables) as if they were data attributes and then creating your hierarchy based on shared attributes. Always create hierarchies based on shared behaviors, side.
David West
sort, doSort, basicSort, doBasicSort, primitiveSort, superBasicPrimitiveSort, who does the real work?
TL;DR: Shortcuts for mini wrappers shout for better solutions.
<?
final class Calculator {
private $cachedResults;
function computeSomething() {
if (isset($this->cachedResults)) {
return $this->cachedResults;
}
$this->cachedResults = $this->logAndComputeSomething();
}
private function logAndComputeSomething() {
$this->logProcessStart();
$result = $this->basicComputeSomething();
$this->logProcessEnd();
return $result;
}
private function basicComputeSomething() {
/// Do Real work here
}
}
<?
final class Calculator {
function computeSomething() {
// Do Real work here since I am Compute!
}
}
//Clean and cohesive class, single responsibility
final class CalculatorDecoratorCache {
private $cachedResults;
private $decorated;
function computeSomething() {
if (isset($this->cachedResults)) {
return $this->cachedResults;
}
$this->cachedResults = $this->decorated->computeSomething();
}
}
final class CalculatorDecoratorLogger {
private $decorated;
function computeSomething() {
$this->logProcessStart();
$result = $this->decorated->computeSomething();
$this->logProcessEnd();
return $result;
}
}
We can instruct our static linters to find wrapping methods if they follow conventions like doXXX(), basicXX() etc.
The primary disadvantage of Wrap Method is that it can lead to poor names. In the previous example, we renamed the pay method dispatchPay() just because we needed a different name for code in the original method.
Classes are handy. We can call them and invoke them any time. Is this good?
TL;DR: Don't use your classes as a global point of access.
<?
final class StringUtilHelper {
static function reformatYYYYDDMMtoYYYYMMDD($date) {
}
}
class Singleton {
}
final class DatabaseAccessor extends Singleton {
}
<?
namespace Date;
final class DateFormatter {
function reformatYYYYDDMMtoYYYYMMDD(Date $date) {
}
//function is not static since class single responsibility is to create instances and not be a library of utils
}
namespace OracleDatabase;
class DatabaseAccessor {
//Database is not a singleton and it is namespace scoped
}
Write shy code — modules that don't reveal anything unnecessary to other modules and that don't rely on other modules' implementations.
Dave Thomas