Conscious Coupling

60
Conscious Coupling Building Software that Lasts Ciaran McNulty at SymfonyLive London

Transcript of Conscious Coupling

Page 1: Conscious Coupling

Conscious CouplingBuilding Software that LastsCiaran McNulty at SymfonyLive London

Page 2: Conscious Coupling

Me

Hi, I'm Ciaran and I'm a PHP developerI am a consultant with Inviqa

I maintain PhpSpec

Page 3: Conscious Coupling

My early period:Follow the framework!

Page 4: Conscious Coupling

SymfonyLive London 2013Konstantin Kudryashov and Marcello Duarte -The Framework as an Implementation Detail

Page 5: Conscious Coupling

SymfonyLive London 2014Matthias Noback - The Naked Bundle

Page 6: Conscious Coupling

My middle period:Decouple all the things!

Page 7: Conscious Coupling

Modelling by ExampleKonstantin Kudryashov (again)

Page 8: Conscious Coupling

My current period:Couple some of the things!

Page 9: Conscious Coupling

What is coupling?

Page 10: Conscious Coupling

class TaxiDispatcher { function dispatch (Car $car, $destination) { $this->chargeCustomer(); $car->goTo($destination); }}

Page 11: Conscious Coupling
Page 12: Conscious Coupling
Page 13: Conscious Coupling
Page 14: Conscious Coupling

Problems with dependencies

—Changes to Car mean changes to Dispatcher—Can't reuse Dispatcher with new vehicles

Page 15: Conscious Coupling

interface Vehicle{ public function goTo($destination);}

class TaxiDispatcher { function dispatch (Vehicle $vehicle, $destination) { $this->chargeCustomer(); $vehicle->goTo($destination); }}

Page 16: Conscious Coupling
Page 17: Conscious Coupling
Page 18: Conscious Coupling
Page 19: Conscious Coupling
Page 20: Conscious Coupling

Benefits of abstraction

—Now we only need to rewrite Dispatcher and Car when Vehicle changes

—Vehicle can be very stable; it's just an interface—Can make new transportation types that

implement Vehicle

Page 21: Conscious Coupling

Defining abstractions

—Start with the use case, not the implementation detail

—Contract should be a simple as possible—Contract should focus on responsibilities—Hide details of underlying APIs

Page 22: Conscious Coupling

Example - upgrade eligibility

Bad abstraction:interface HttpClient{ public function getData : array ($url, $parameters);}

Page 23: Conscious Coupling

Example - upgrade eligibility

Better abstraction:interface UpgradeEligibilityChecker{ public function getContractId : int ($phoneNumber); public function isEligibleForUpgrade : bool ($contractId);}

Page 24: Conscious Coupling

Example - upgrade eligibility

Best abstraction:interface UpgradeEligibilityChecker{ public function isEligibleForUpgrade : bool ($phoneNumber);}

Page 25: Conscious Coupling

Abstraction via interfaces

—You still need to know what methods to call—Caller has to respond to changes in the callee

Page 26: Conscious Coupling

Taking it further:Events and Commands

Page 27: Conscious Coupling

—Migrate actions from method calls to objects—Depend on a bus rather than depending on

contracts—Don't know anything about what handles the

action

Page 28: Conscious Coupling

Events

Direct coupling:$notifier->notifyLawyersAboutPurchase($id, $item, $cost);

Event style (symfony/event-dispatcher):$eventDispatcher->dispatch( 'item.purchased', new ItemWasPurchased($id, $item, $cost););

Page 29: Conscious Coupling

Commands

Use case / service style:$invoiceApprover->approveInvoice(1234);Command style (thephpleague/tactician):$commandBus->handle( new ApproveInvoice(1234););

Page 30: Conscious Coupling

Advantages of decoupling via abstractions

—Cleaner APIs—Swappable components—Separation of concerns—Easier to test—No 'ripple effect' around changes

Page 31: Conscious Coupling

Disadvantages of decoupling via abstractions

—Makes execution flow harder to follow—Adds more complexity (more files in codebase)—Cognitive cost of thinking of good abstractions

Page 32: Conscious Coupling

Decoupling from infrastructure

Page 33: Conscious Coupling

—Abstractions are going to change when the use cases change

—Interfaces are more tightly coupled to code that uses them

—Interfaces 'belong' in the same architectural boundary as the code that uses them.

Page 34: Conscious Coupling
Page 35: Conscious Coupling
Page 36: Conscious Coupling

FrameworksCoupling to other people's code

Page 37: Conscious Coupling

Highly coupled frameworks

Some frameworks let you go really quickly by coupling directly to them.

You probably won't be able to reuse your code without considerable effort.

—Drupal—Magento—Wordpress

Page 38: Conscious Coupling

More coupled framworks

Some frameworks let you go faster when you adopt their conventions.

You can reuse your code with a fair amount of additional effort.

—Symfony (1)—CakePHP—Laravel

Page 39: Conscious Coupling

More decoupled frameworks

Some frameworks encourage decoupling so your code is more reusable.

You will go a little slower because you need to explicitly configure things

—Symfony 2+—Zend Framework 2+

Page 40: Conscious Coupling

Very decoupled frameworks

Some frameworks are extremely decoupled so code is almost entirely reusable.

You almost have to construct the entire framework yourself from components - this can be hard!

—D.I.Y.—Silex—Zend Expressive

Page 41: Conscious Coupling

Decoupling inside your system

Page 42: Conscious Coupling

Only decouple where you need to(how do we know where that is?)

Page 43: Conscious Coupling

Coupled code get painful when change happensDecoupled code was wasted effort when change doesn't happen

Page 44: Conscious Coupling

Where does change come from?

Page 45: Conscious Coupling

Where does change come from?

People!

Page 46: Conscious Coupling

Organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations— Melvin Conway, 1967

Page 47: Conscious Coupling
Page 48: Conscious Coupling
Page 49: Conscious Coupling
Page 50: Conscious Coupling
Page 51: Conscious Coupling

Decouple your system to respond to different streams of change

Page 52: Conscious Coupling
Page 53: Conscious Coupling
Page 54: Conscious Coupling

Service-orientation

—Good abstractions help you define boundaries—Abstractions inside a monolith are easier to move

when you get it wrong—Share values, not entities—Don't share persistence

Page 55: Conscious Coupling
Page 56: Conscious Coupling

Context mapping

—Identify subdomains—Identify which are:

—Core subdomains—Supporting subdomains—Generic subdomains

—Mirror the structure in your architecture

Page 57: Conscious Coupling

The bad news:You will get it wrong

You only find out afterwards

Page 58: Conscious Coupling

The good news:It's not just you

Page 59: Conscious Coupling

Things to check out

—Context Mapping—Hexagonal Architecture—Modelling by Example

Page 60: Conscious Coupling

Thank you!

—@ciaranmcnulty—Lead Maintainer of PhpSpec—Trainer and Coach at Inviqa

Questions?