How to Write Code That Embraces Change

How to Write Code That Embraces Change

Tutorial Details
  • Difficulty: Advanced
  • Completion Time: 1 Hour

Writing code, which is easy to change is the Holy Grail of programming. Welcome to programming nirvana! But things are much more difficult in reality: source code is difficult to understand, dependencies point in countless directions, coupling is annoying, and you soon feel the heat of programming hell. In this tutorial, we will discuss a few principles, techniques and ideas that will help you write code that is easy to change.


Some Object-Oriented Concepts

Object-oriented programming (OOP) became popular, due to its promise of code organization and reuse; it utterly failed in this endeavor. We’ve been using OOP concepts for many years now, yet we continue to repeatedly implement the same logic in our projects. OOP introduced a set of good basic principles which, if properly used, can lead to better, cleaner code.

Cohesion

The things that belong together should be kept together; otherwise, they should be moved elsewhere. This is what the term, cohesion, refers to. The best example of cohesion can be demonstrated with a class:

class ANOTCohesiveClass {
	private $firstNumber;
	private $secondNumber;
	private $length;
	private $width;

	function __construct($firstNumber, $secondNumber) {
		$this->firstNumber = $firstNumber;
		$this->secondNumber = $secondNumber;
	}

	function setLength($length) {
		$this->length = $length;
	}

	function setHeight($height) {
		$this->width = $height;
	}

	function add() {
		return $this->firstNumber + $this->secondNumber;
	}

	function subtract() {
		return $this->firstNumber - $this->secondNumber;
	}

	function area() {
		return $this->length * $this->width;
	}
}

This example defines a class with fields that represent numbers and sizes. These properties, judged only by their names, do not belong together. We then have two methods, add() and substract(), which operate on only the two number variables. We further have an area() method, that operates on the length and width fields.

It’s obvious that this class is responsible for separate groups of information. It has very low cohesion. Let’s refactor it.

class ACohesiveClass {
	private $firstNumber;
	private $secondNumber;

	function __construct($firstNumber, $secondNumber) {
		$this->firstNumber = $firstNumber;
		$this->secondNumber = $secondNumber;
	}
	function add() {
		return $this->firstNumber + $this->secondNumber;
	}

	function subtract() {
		return $this->firstNumber - $this->secondNumber;
	}
}

This is a highly cohesive class. Why? Because every section of this class belongs with one another. You should strive for cohesion, but beware, it’s can be difficult to achieve.

Orthogonality

In simple terms, orthogonality refers to the isolation or elimination of side effects. A method, class or module that changes the state of other unrelated classes or modules is not orthogonal. For example, an airplane’s black box is orthogonal. It has its inner functionality, inner power source, microphones and sensors. It has no effect on the airplane it resides in, or in the exterior world. It only provides a mechanism to record and retrieve flight data.

An example of one such non-orthogonal system is your car’s electronics. Increasing your vehicle’s speed has several side-effects, such as increasing radio volume (among other things). Speed is not orthogonal to the car.

class Calculator {
	private $firstNumber;
	private $secondNumber;

	function __construct($firstNumber, $secondNumber) {
		$this->firstNumber = $firstNumber;
		$this->secondNumber = $secondNumber;
	}
	function add() {
		$sum = $this->firstNumber + $this->secondNumber;
		if ($sum > 100) {
			(new AlertMechanism())->tooBigNumber($sum);
		}
		return $sum;
	}

	function subtract() {
		return $this->firstNumber - $this->secondNumber;
	}
}
class AlertMechanism {
	function tooBigNumber($number) {
		echo $number . 'is too big!';
	}
}

In this example, the Calculator class’s add() method exhibits unexpected behavior: it creates an AlertMechanism object and calls one of its methods. This is unexpected and unwanted behavior; library consumers will never expect a message printed to the screen. Instead, they only expect the sum of the provided numbers.

class Calculator {
	private $firstNumber;
	private $secondNumber;

	function __construct($firstNumber, $secondNumber) {
		$this->firstNumber = $firstNumber;
		$this->secondNumber = $secondNumber;
	}
	function add() {
		return $this->firstNumber + $this->secondNumber;
	}

	function subtract() {
		return $this->firstNumber - $this->secondNumber;
	}
}
class AlertMechanism {
	function checkLimits($firstNumber, $secondNumber) {
		$sum = (new Calculator($firstNumber, $secondNumber))->add();
		if ($sum > 100) {
			$this->tooBigNumber($sum);
		}
	}

	function tooBigNumber($number) {
		echo $number . 'is too big!';
	}
}

This is better. AlertMechanism has no effect on Calculator. Instead, AlertMechanism uses whatever it needs in order to determine if an alert should be issued.

Dependency and Coupling

In most cases, these two words are interchangeable; but, in some cases, one term is preferred over another.

So what is a dependency? When object A needs to use object B, in order to perform its prescribed behavior, we say that A depends on B. In OOP, dependencies are extremely common. Objects frequently work with and depend on one another. So, while eliminating dependency is a noble pursuit, it is nearly impossible to do so. Controlling dependencies and reducing them is, however, preferable.

The terms, heavy-coupling and loose-coupling, usually refer to how much an object depends on other objects.

In a loosely-coupled system, changes in one object have a reduced effect on the other objects which depend on it. In such systems, classes depends on interfaces instead of concrete implementations (we will talk more about that later). This is why loosely-coupled systems are more open to modifications.

Coupling in a Field

Let’s consider an example:

class Display {

	private $calculator;

	function __construct() {
		$this->calculator = new Calculator(1,2);
	}

}

It’s common to see this type of code. A class, Display in this case, depends upon the Calculator class by directly referencing that class. In the above code, Display‘s $calculator field is of type Calculator. The object that field contains is a result of directly calling Calculator‘s constructor.

Coupling by Accessing the Other Class Methods

Review the following code for a demonstration of this kind of coupling:

class Display {

	private $calculator;

	function __construct() {
		$this->calculator = new Calculator(1, 2);
	}

	function printSum() {
		echo $this->calculator->add();
	}

}

The Display class calls the Calculator object’s add() method. This is another form of coupling, because one class accesses the other’s method.

Coupling by Method Reference

You can couple classes with method references, too. For example:

class Display {

	private $calculator;

	function __construct() {
		$this->calculator = $this->makeCalculator();
	}

	function printSum() {
		echo $this->calculator->add();
	}

	function makeCalculator() {
		return new Calculator(1, 2);
	}

}

It’s important to note that the makeCalculator() method returns a Calculator object. This is a dependency.

Coupling by Polymorphism

Inheritance is probably the strongest form of dependency:

class AdvancedCalculator extends Calculator {

	function sinus($value) {
		return sin($value);
	}

}

Not only can AdvancedCalculator not do its job without Calculator, but it couldn’t even exist without it.

Reducing Coupling by Dependency Injection

One can reduce coupling by injecting a dependency. Here’s one such example:

class Display {

	private $calculator;

	function __construct(Calculator $calculator = null) {
		$this->calculator = $calculator ? : $this->makeCalculator();
	}

// ... //

}

By injecting the Calculator object through Display‘s constructor, we reduced Display‘s dependency upon the Calculator class. But this is only half of the solution.

Reducing Coupling with Interfaces

We can further reduce coupling by using interfaces. For example:

interface CanCompute {
	function add();
	function subtract();
}

class Calculator implements CanCompute {

	private $firstNumber;
	private $secondNumber;

	function __construct($firstNumber, $secondNumber) {
		$this->firstNumber = $firstNumber;
		$this->secondNumber = $secondNumber;
	}

	function add() {
		return $this->firstNumber + $this->secondNumber;
	}

	function subtract() {
		return $this->firstNumber - $this->secondNumber;
	}

}

class Display {

	private $calculator;

	function __construct(CanCompute $calculator = null) {
		$this->calculator = $calculator ? : $this->makeCalculator();
	}

	function printSum() {
		echo $this->calculator->add();
	}

	function makeCalculator() {
		return new Calculator(1, 2);
	}

}

You can think of ISP as a higher-level cohesion principle.

This code introduces the CanCompute interface. An interface is as abstract as you can get in OOP; it defines the members that a class must implement. In the case of the above example, Calculator implements the CanCompute interface.

Display‘s constructor expects an object that implements CanCompute. At this point, Display‘s dependency with Calculator is effectively broken. At any time, we can create another class that implements CanCompute and pass an object of that class to Display‘s constructor. Display now depends only on the CanCompute interface, but even that dependency is optional. If we pass no arguments to Display‘s constructor, it will simply create a classic Calculator object by calling makeCalculator(). This technique is frequently used, and is extremely helpful for test-driven development (TDD).


The SOLID Principles

SOLID is a set of principles for writing clean code, which then makes it easier to change, maintain and extend in the future. They are recommendations that, when applied to source code, have a positive effect on maintainability.

A Little History

The SOLID principles, also known as Agile principles, were initially defined by Robert C. Martin. Even though he did not invent all of these principles, he was the one who put them together. You can read more about them in his book: Agile Software Development, Principles, Patterns, and Practices. SOLID’s principles cover a wide array of topics, but I will present them in as simple a way as I’m capable. Feel free to ask for additional details in the comments, if needed.

Single Responsibility Principle (SRP)

A class has a single responsibility. This may sound simple, but it can sometimes be difficult to understand and put into practice.

class Reporter {
	function generateIncomeReports();
	function generatePaymentsReports();
	function computeBalance();
	function printReport();
}

Who do you think benefits from this class’ behavior? Well, an accounting department is an option (for the balance), the finance department may be another (for income/payment reports), and even the archiving department could print and archive the reports.

There are four reasons why you might have to change this class; each department may want their respective methods customized for their needs.

The SRP recommends breaking such classes into smaller, beahvior-specific classes, each having just one reason to change. Such classes tend to be highly cohesive and loosely coupled. In a sense, SRP is cohesion defined from the point of view of the users.

Open-Closed Principle (OCP)

Classes (and modules) should welcome the extension of their functionality, as well as resist modifications of their current functionality. Let’s play with the classic example of an electric fan. You have a switch and you want to control the fan. So, you could write something along the lines of:

class Switch_ {

	private $fan;

	function __construct() {
		$this->fan = new Fan();
	}

	function turnOn() {
		$this->fan->on();
	}

	function turnOff() {
		$this->fan->off();
	}

}

Inheritance is probably the strongest form of dependency.

This code defines a Switch_ class that creates and controls a Fan object. Please note the underscore after “Switch_”. PHP doesn’t allow you to define a class with the name “Switch.”

Your boss decides that he wants to control the light with the same switch. This is a problem, because you have to change Switch_.

Any modifications to existing code is a risk; other parts of the system may be affected and require even further modification. It is always preferable to leave existing functionality alone, when adding new functionlaity.

In OOP terminology, you can see that Switch_ has a strong dependency on Fan. This is where our problem lies, and where we should make our changes.

interface Switchable {

	function on();

	function off();
}

class Fan implements Switchable {

	public function on() {
		// code to start the fan
	}

	public function off() {
		// code to stop the fan
	}

}

class Switch_ {

	private $switchable;

	function __construct(Switchable $switchable) {
		$this->switchable = $switchable;
	}

	function turnOn() {
		$this->switchable->on();
	}

	function turnOff() {
		$this->switchable->off();
	}

}

This solution introduces the Switchable interface. It defines the methods that all switch-enabled objects need to implement. The Fan implements Switchable, and Switch_ accepts a reference to a Switchable object within its constructor.

How does this help us?

First, this solution breaks the dependency between Switch_ and Fan. Switch_ has no idea that it starts a fan, nor does it care to. Second, introducing a Light class will not affect Switch_ or Switchable. Do you want to control a Light object with your Switch_ class? Simply create a Light object and pass it to Switch_, like this:

class Light implements Switchable {

	public function on() {
		// code to turn ligh on
	}

	public function off() {
		// code to turn light off
	}

}

class SomeWhereInYourCode {

	function controlLight() {
		$light = new Light();
		$switch = new Switch_($light);
		$switch->turnOn();
		$switch->turnOff();
	}

}

Liskov Substitution Principle (LSP)

LSP states that a child class should never break the functionality of the parent class. This is extremely important because consumers of a parent class expect the class to behave in a certain way. Passing a child class to a consumer should just work and not affect the original functionality.

This is confusing at first glance, so let’s look at another classic example:

class Rectangle {

	private $width;
	private $height;

	function setWidth($width) {
		$this->width = $width;
	}

	function setHeigth($heigth) {
		$this->height = $heigth;
	}

	function area() {
		return $this->width * $this->height;
	}

}

This example defines a simple Rectangle class. We can set its height and width, and its area() method provides the rectangle’s area. Using the Rectangle class could look like the following:

class Geometry {

	function rectArea(Rectangle $rectangle) {
		$rectangle->setWidth(10);
		$rectangle->setHeigth(5);
		return $rectangle->area();
	}

}

The rectArea() method accepts a Rectangle object as an argument, sets its height and width, and returns the shape’s area.

In school, we’re taught that squares are rectangles. This hints that if we model our program to our geometrical object, a Square class should extend a Rectangle class. How would such a class look like?

class Square extends Rectangle {
	// What code to write here?
}

I have a hard time figuring out what to write in the Square class. We have several options. We could override the area() method and return the square of $width:

class Rectangle {

	protected $width;
	protected $height;

	// ... //
}

class Square extends Rectangle {
	function area() {
		return $this->width ^ 2;
	}
}

Note that I changed Rectangle‘s fields to protected, giving Square access to those fields. This looks reasonable from a geometrical point-of-view. A square has equal sides; returning the square of width is reasonable.

However, we have a problem from a programming point-of-view. If Square is a Rectangle, we should have no problem feeding it into the Geometry class. But, by doing so, you can see that Geometry‘s code doesn’t make much sense; it sets two different values for height and width. This is why a square is not a rectangle in programming. LSP violated.

Interface Segregation Principle (ISP)

Unit tests should run fast – very fast.

This principle concentrates on breaking large interfaces into small, specialized interfaces. The basic idea is that different consumers of the same class should not know about the different interfaces – only the interfaces the consumer needs to use. Even if a consumer does not directly use all the public methods on an object, it still depends on all the methods. So why not provide interfaces with that only declare the methods that each user needs?

This is in close accordance that interfaces should belong to the clients and not to the implementation. If you tailor your interfaces to the consuming classes, they will respect ISP. The implementation itself can be unique, as a class can implement several interfaces.

Let’s imagine that we implement a stock market application. We have a broker that buys and sells stocks, and it can report its daily earnings and losses. A very simple implementation would include something like a Broker interface, a NYSEBroker class that implements Broker and a couple of user interface classes: one for creating transactions (TransactionsUI) and one for reporting (DailyReporter). The code for such a system could be similar to the following:

interface Broker {

	function buy($symbol, $volume);

	function sell($symbol, $volume);

	function dailyLoss($date);

	function dailyEarnings($date);

}

class NYSEBroker implements Broker {

	public function buy($symbol, $volume) {
		// implementsation goes here
	}

	public function currentBalance() {
		// implementsation goes here
	}

	public function dailyEarnings($date) {
		// implementsation goes here
	}

	public function dailyLoss($date) {
		// implementsation goes here
	}

	public function sell($symbol, $volume) {
		// implementsation goes here
	}

}

class TransactionsUI {

	private $broker;

	function __construct(Broker $broker) {
		$this->broker = $broker;
	}

	function buyStocks() {
		// UI logic here to obtain information from a form into $data
		$this->broker->buy($data['sybmol'], $data['volume']);
	}

	function sellStocks() {
		// UI logic here to obtain information from a form into $data
		$this->broker->sell($data['sybmol'], $data['volume']);
	}

}

class DailyReporter {

	private $broker;

	function __construct(Broker $broker) {
		$this->broker = $broker;
	}

	function currentBalance() {
		echo 'Current balace for today ' . date(time()) . "\n";
		echo 'Earnings: ' . $this->broker->dailyEarnings(time()) . "\n";
		echo 'Losses: ' . $this->broker->dailyLoss(time()) . "\n";
	}

}

While this code may work, it violates the ISP. Both DailyReporter and TransactionUI depend on the Broker interface. However, they each only use a fraction of the interface. TransactionUI uses the buy() and sell() methods, while DailyReporter uses the dailyEarnings() and dailyLoss() methods.

You may argue that Broker is not cohesive because it has methods that are unrelated, and thus don’t belong together.

This may be true, but the answer depends on the implementations of Broker; selling and buying may be strongly related to current losses and earnings. For example, you may not be allowed to buy stocks if you are losing money.

You may also argue that Broker also violates SRP. Because we have two classes that use it in different ways, there may be two different users. Well, I say no. The only user is probably the actual broker. He/she wants to buy, sell, and view their current funds. But again, the actual answer depends on the whole system and business.

ISP is surely violated. Both UI classes depend on the whole Broker. This is a common problem, if you think interfaces belong to their implementations. However, shifting your point-of-view can suggest the following design:

interface BrokerTransactions {

	function buy($symbol, $volume);

	function sell($symbol, $volume);
}

interface BrokerStatistics {

	function dailyLoss($date);

	function dailyEarnings($date);
}

class NYSEBroker implements BrokerTransactions, BrokerStatistics {

	public function buy($symbol, $volume) {
		// implementsation goes here
	}

	public function currentBalance() {
		// implementsation goes here
	}

	public function dailyEarnings($date) {
		// implementsation goes here
	}

	public function dailyLoss($date) {
		// implementsation goes here
	}

	public function sell($symbol, $volume) {
		// implementsation goes here
	}

}

class TransactionsUI {

	private $broker;

	function __construct(BrokerTransactions $broker) {
		$this->broker = $broker;
	}

	function buyStocks() {
		// UI logic here to obtain information from a form into $data
		$this->broker->buy($data['sybmol'], $data['volume']);
	}

	function sellStocks() {
		// UI logic here to obtain information from a form into $data
		$this->broker->sell($data['sybmol'], $data['volume']);
	}

}

class DailyReporter {

	private $broker;

	function __construct(BrokerStatistics $broker) {
		$this->broker = $broker;
	}

	function currentBalance() {
		echo 'Current balace for today ' . date(time()) . "\n";
		echo 'Earnings: ' . $this->broker->dailyEarnings(time()) . "\n";
		echo 'Losses: ' . $this->broker->dailyLoss(time()) . "\n";
	}

}

This actually makes sense and respects the ISP. DailyReporter depends only on BrokerStatistics; it doesn’t care and does not have to know about any selling and buying operations. TransactionsUI, on the other hand, knows only about buying and selling. The NYSEBroker is identical to our previous class, except it now implements the BrokerTransactions and BrokerStatistics interfaces.

You can think of ISP as a higher-level cohesion principle.

When both UI classes depended on the Broker interface, they were similar to two classes, each having four fields, of which two were used in a method and the other two in another method. The class would have not been very cohesive.

A more complex example of this principle can be found in one of Robert C. Martin’s first papers on the subject: The Interface Segregation Principle.

Dependency Inversion Principle (DIP)

This principle states that high-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend upon details; details should depend upon abstractions. Put simply, you should depend on abstractions as much as possible and never on concrete implementations.

The trick with DIP is that you want to reverse the dependency, but always want to keep the flow of control. Let’s review our example from the OCP (the Switch and Light classes). In the original implementation, we had a switch directly controlling a light.

As you can see, both dependency and control flow from Switch toward Light. While this is what we want, we do not want to directly depend on Light. So we introduced an interface.

It’s amazing how simply introducing an interface makes our code respect both DIP and OCP. As you can see no, class depends on the concrete implementation of Light, and both Light and Switch depend on the Switchable interface. We inverted the dependency, and the flow of control was unchanged.


High Level Design

Another important aspect of your code is your high-level design and general architecture. An entangled architecture produces code that is hard to modify. Keeping a clean architecture is essential, and the first step is understanding how to separate your code’s different concerns.

In this image, I attempted to summarize the main concerns. In the center of the schema is our business logic. It should be well-isolated from the rest of the world, and be able to work and behave as expected without the existence of any of the other parts. See it as orthogonality on a higher level.

Starting from the right, you have your “main” – the entry point to the application – and the factories that create objects. An ideal solution would get its objects from specialized factories, but that is mostly impossible or impractical. Still, you should use factories when you have the opportunity to do so, and keep them outside of your business logic.

Then, at the bottom (in orange), we have persistence (databases, file accesses, network communications) for the purpose of persisting information. No object in our business logic should know how persistence works.

On the left is the delivery mechanism.

An MVC, like Laravel or CakePHP, should only be the delivery mechanism, nothing more.

This lets you swap one mechanism with another without touching your business logic. This may sound outrageous to some of you. We’re told that our business logic should be placed in our models. Well, I disagree. Our models should be “request models”, i.e. dumb data objects used for passing information from MVC to the business logic. Optionally, I see no problem including input validation in the models, but nothing more. Business logic should not be in the models.

When you look at your application’s architecture or directory structure, you should see a structure that suggests what the program does as opposed to what framework or database you used.

Lastly, make sure that all dependencies point toward our business logic. User interfaces, factories, databases are very concrete implementations, and you should never depend on them. Inverting the dependencies to point toward our business logic modularizes our system, allowing us to change dependencies without modifying the business logic.


Some Thoughts About Design Patterns

Design patterns play an important role in making code easier to modify, by offering a common design solution that every programmer can understand. From a structural point-of-view, design patterns are obviously advantageous. They are well tested and thought-out solutions.

If you’d like to learn more about design patterns, I created a Tuts+ Premium course on them!


The Force of Testing

Test-Driven Development encourages writing code that is easy to test. TDD forces you to respect most of the above principles in order to make your code easy to test. Injecting dependencies and writing orthogonal classes are essential; otherwise, you end up with huge test methods. Unit tests should run fast – very fast, actually, and everything that is not tested should be mocked. Mocking many complex classes for a simple test can be overwhelming. So when you find yourself mocking ten objects to test a single method on a class, you may have a problem with your code… not your test.


Final Thoughts

At the end of the day, it all comes down to how much you care about your source code. Having technical knowledge is not enough; you need to apply that knowledge again and again, never being 100% satisfied with your code. You have to want to make your code easy to maintain, clean and open to change.

Thanks for reading and feel free to contribute your techniques in the comments below.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://brayanrastelli.com/ Brayan Rastelli

    Awesome article, thanks a lot !

  • http://digitbeing.com/ Prabhakar Bhat

    Why do I read embarrass whenever I see embrace?

    Nice article!

    • http://www.facebook.com/soos.gabor86 Soós Gábor

      cuz u are reading an embarassing article :)

  • David G

    The link to the Agile practices book doesn’t work right. It’s the shortened envato link tagged on to the end of the article’s link.

    • jeff_way

      Thanks, David. Fixed.

  • http://twitter.com/centerdrive Todd Smith-Salter

    Thanks for the superb write up Patkos. That really made a few concepts about OOP and code organization much clearer to me.

  • http://www.facebook.com/hrvoje.krbavac Hrvoje Krbavac

    Nice One! :) Thanks!

  • http://twitter.com/mamunabms Abdullah Al Mamun

    Thanks. :)

  • pixelBender67

    Really good article, reminds me of my into to programming class with AS3

  • danielcs

    A very well written and illustrated article, congratulations!!

  • http://www.facebook.com/elderhenrique Elder Henrique Souza

    Awesome article! I was happy to notice that even if I haven’t heard of SOLID principles before, I was implementing them already, much because of what you said, you should never be happy about your code, always trying to optimize and improve, I know there a lot of others programmers that organically achieved the same results, thus proving in my opinion the validity of such principles. I knew I was in the right direction just because I sensed my code easier to modify and extend, and I will continue to do so.

  • http://www.facebook.com/nickmokisasian Nic Mok

    Sweet article. SOLID is the way to go now!

  • Ritz

    Great article. Thanks Patkos

  • Hamed

    Thanks for your great article.

  • http://www.facebook.com/soos.gabor86 Soós Gábor

    well written nice article, PHP community needs more of this

  • Kise

    Thank you, this is the first article that actually made sense about the interfaces and how they should be used.

  • MPinteractiv

    great article

  • Vlad Costea

    Great article. However I’m still confused about something. If Laravel should only be my delivery mechanism, does it mean that I shouldn’t use it’s eloquent ORM and create my own database interaction system ?

    • Patkos Csaba
      Author

      The short answer is yes. But I am not quite familiar with Laravel. If it works like any other MVC framework I would apply the same rules to it. The thing is, as long as you have small projects, mostly CRUD, without any significant business logic you can get away with logic at model level.

      However when you start building bigger and more entangled systems you don’t want to rely on Laravel or on any other MVC framework. What do you do if you realize, after say 6 months of heavy development and deployment that your initial choice of MVC is not good enough for you? What if it is too slow, too buggy or simply does not have some features your business absolutely needs?

      If your design is decoupled enough, you can ditch one MVC and install another one.

      But, if you use Laravel’s ORM in a way that it persists you business logic objects and not your models than it is OK. Just be sure you decouple any persistence service / technique properly so if you need to change it you won’t have to change your business logic. (see Gateway, Adapter, Proxy and Bridge design patterns about persistence).

      • http://dextructables.com/ Judas

        Check this screencast where Taylor, the creator of Laravel, explains how you can use interfaces and automatic dependency injection to decouple different implementations. It’s cool. http://vimeo.com/53029232

    • jass

      very interesting

  • elkaz

    I’m really enjoying all your articles so far Patkos. Keep them coming :)

  • Jesse Bunch

    Thanks, Patkos. One question: do you have, or know of, a PHP open source project or example that uses this type of architecture? Uncle Bob doesn’t seem to have one. It’s difficult to understand this architecture without a real world example.

    • Patkos Csaba
      Author

      I do not have an example, but we do it this way at work at Syneto and believe me it is much better. We were dependent on CakePHP models in the past and at some point it became a nightmare. Now we have an architecture like this and it is much much easier to find what you are looking for, we don’t depend on CakePHP any more and we now where to change what we need to change.

      • keripix

        So are you saying you’re not dependant on any framework at all? How do you achieve this?

        I actually tried to remove any dependency on any MVC framework. But I got stuck when i want to design a model that can remove dependency on any DB implementation? How do I make an interface from that? Or is my approach wrong?

      • Patkos Csaba
        Author

        I do not understand your question. Feel free to contact me by email with more details.

      • http://www.facebook.com/soos.gabor86 Soós Gábor

        In great systems it can be really hard and time consuming to get rid of all the dependencies of a framework

      • Patkos Csaba
        Author

        If you already have a big and badly designed system than the only way I see is to gradually, a little at a time, improve it toward a more decoupled design. If you start fresh you have no excuse regardless of the project’s size.

  • Vivi

    Just another fluff piece that tells us we should use OOP and Design Patterns and in a manner described by the author.
    I think you are trying to teach monkeys to write code.
    It ain’t gonna work.

    • Patkos Csaba
      Author

      Yeah, sure. Feel free to use whatever suites you best.

  • roblevintennis

    Nice OOP coverage. Here’s a free book I just did on Design Patterns that might help tie some these concepts together: roblevintennis.github.com/the-learn-d-developer-design-patterns/

    • michaeldavison3

      Hey – this is great stuff!

      • roblevintennis

        Thanks!

    • http://www.facebook.com/ring801112 Hayden Kim

      nice php example!! thanks!!

  • Gibrain Fakhri

    Nice article Patkos, i like the way you close the article.

    “At the end of the day, it all comes down to how much you care about your
    source code. Having technical knowledge is not enough; you need to
    apply that knowledge again and again, never being 100% satisfied with
    your code. You have to want to make your code easy to maintain, clean
    and open to change.”

  • kris
  • pinkcadillac

    excellent. i never really appreciated the value of interfaces before

  • http://twitter.com/agilius Vlad Nicula

    Good retrospective. There’s one mention though. Square is the base class from a programming point of view, because it’s more simple than the rectangle. A square has just one “value” for it’s lines, while a rectangle has 2 (Rectangle extends Square) and a trapezoid has 4 (Trapezoid extends Rectangle extends Square)

    • Patkos Csaba
      Author

      Yes, you can maybe do that. But on Square you would have a method “setSide($length)” while on Rectangle you would need “setWidth($length)” and “setHeight($length)”. How do you solve that?

      • http://www.facebook.com/iulianalexandru.costeiu Iulian Alexandru Costeiu

        you can add those methods in Rectangle class, override setSlide from Square class

      • Patkos Csaba
        Author

        You mean you would have a Rectangle class with a public method called setSide? What should such a method do? If your Rectangle’s clients doesnt know what a Square is what should they think about $rectangle-> setSide () ?

      • http://profiles.google.com/florin.jurcovici Florin Jurcovici

        How about using the rhombus as the base class? After all, a square is a rhombus with right angles. Or a rectangle with two equal adjacent sides. But wait, a rhombus is a parallelogram with two equal adjacent sides, so a rectangle is just a parallelogram with right angles. What would be the right inheritance hierarchy?

        IMO that’s a nice OO modeling problem – sort of solving multiple inheritance in a language which disallows it. Here’s my take on it: we’re after a hierarchy of geometric shapes, when obviously what we’re looking at is just a mechanism for mixing and matching different constraints to produce various shapes.

        IMO this allows for a nicer approach: a base shape class, modeled as a set of points (it doesn’t have to keep the list of all points it contains, it may just provide a method to tell if a point is or isn’t in the set, or you could apply it to a raster and ask it to pick the raster points which are part of the shape), to which you attach constraints, which determine what points are or aren’t in the set. A square would then be a rectangle constraint mixed with a rhombus constraint, or vice versa. It wouldn’t matter.

        You could have a simple constraint: a line segment being part of the shape, with a specified length for each segment. Combining this with a rectangle constraint which just enforces right angles and a rhombus constraint which says all sides must be of equal length gives you a square. Combining two of the exotic constraints with a rectangle constraint gives you a rectangle. Combining two such constraints with a parallelogram constraint which just says that opposite sides must be parallel gives you a parallelogram.

        And of course, implementing the constraint solver in an efficient way would be quite an interesting challenge.

      • Patkos Csaba
        Author

        It would be quite interesting to play with some code on this topic.

      • Jane

        How about this: Keep Square as a subclass and add method setSide(side){set width=height=side}? Great article. Thanks.

  • Mauro

    Thanks for writing this useful article!!

  • http://cubicleninjas.com/ Tyler Etters

    Another principal I’m quite fond of is YAGNI: Ya Ain’t Gonna Need It. Don’t build something that you think you *might* need one day. You have enough that needs to be built *right now*.

    • Patkos Csaba
      Author

      Yagni is very useful. However I’ve seen it to have a slight backfire. Many people tend to see it as a recommendation to not think about the future, and there is a big difference betveen not thinking about a possible feature and conciosly deferring it to the last possible moment.

      • http://cubicleninjas.com/ Tyler Etters

        Excellent point. “Ya ain’t gonna need it… unless you will.” I suppose the spirit of YAGNI is meant to deter us from wild goose chases. Don’t build NoSQL support if your primary SQL strategy isn’t implemented. Don’t bunch of JSON helpers if your MVP serves up HTML pages, etc.

  • guilherme

    thank you. good code examples, well written article

  • A Suresh Kumar

    Nice Article, very easy to understand SOLID Principles using examples. Nice Work

  • DinkoMiletic

    Erm… We should use Laravel only as a delivery mechanism? I don’t approve this nor Laravel makers. Actually i think Laravel uses/implements everything you mentioned in your article. Laravel actually help us to use those principles.

  • http://pulse.yahoo.com/_USUGCT64XOP6YLPWECVEFLTYWM Jt

    Cool ideas and thanks for the read.

    As some might say:
    Software as a religion, with the one and only way to do things. All others lead straight to hell. (Strict order, but absolutely helpless when something happens that is not dealt with in their particular bible)

  • http://twitter.com/emerazea emerazea

    As a PHP-toddler, this was a really insightful and informative article. I know I’ll be referencing it often as I try to mature as a developer. Thank you.

    I have only one question after reading this piece, and that is “what is ‘business logic’?”

    • Patkos Csaba
      Author

      Business logic is the piece of your code, the set of classes and methods, that are responsible to solve your business problems. For example if you have an online webshop your business logic will be all the stuff related to manipulate the products (receive, sell, get payed, pay your providers, keep track of products and so on). If you have an accounting application your business logic fill implement the accounting rules and laws of your country together with mechanisms to solve your in-company accounting problems. If you are building an auto pilot for an airplane your business logic will be the algorithm dictating the actions the auto-pilot has to take to keep the plane flying or land it safely.

      All these are business logics. All applications however usually have some common concepts and secondary concerns that are not part of your business. Such things are user interfaces, delivery mechanisms, persistence solutions and so on.

      • http://twitter.com/emerazea emerazea

        Thanks for responding. So the idea is to make sure that things essential to the business are have as few dependencies as possible so that upgrades and overhauls can leave them unaffected?

      • Patkos Csaba
        Author

        Yes. This also allows you to change external things without changing business logic. For example switch from MySQL to another data storage type. Provide different user interfaces like Web, desktop UI, console, etc. … But I think you’ve got the idea.

  • ChadF

    Cohesion

    . . .
    function setHeight($height) {
    $this->width = $height;
    }
    . . .

    Hmm.. ‘width = height’. Typo? =)

    • Patkos Csaba
      Author

      I check and recheck my code so many times before submitting an article and still sometimes there are little mistakes that just slip in. That is a typo, well spotted, however it does not affect the code’s correctness from syntactical point of view or from the subject’s (cohesion) point of view. It’s just a lexically strange code there :)

  • http://www.facebook.com/egor.konoval Egor Konoval

    The best SOLID principles explanation ever! Thanks for a lot of examples!

  • http://www.facebook.com/seans.ridly Sansar Maske

    Great Article !