#PackageDesignPrinciples

November 28th 2016 – viscaweb.com/meetings

#PackageDesignPrinciples

Part 1

Why ?

#PackageDesignPrinciples

Classes / Packages

SOLID principles for classes

Package Design principles for packages

#PackageDesignPrinciples

What is a package ?

Unit of distribution of a software

#PackageDesignPrinciples

Why a package ?

Organize classes in larger systems to make them more organized and manageable

#PackageDesignPrinciples

Statements

Functions

Classes

Packages

Systems

#PackageDesignPrinciples

Part 2

How ?

#PackageDesignPrinciples

Hight cohesion

Low coupling

#PackageDesignPrinciples

Cohesion

Sense of belonging together

#PackageDesignPrinciples

The Release/reuse equivalence principle

The granule of reuse is the granule of release

#PackageDesignPrinciples

  • VCS
  • Package definition (composer.json, ...)
  • Semantic versioning
  • Backward compatibility
  • README, LICENSE, ...
  • Tests
  • CI

#PackageDesignPrinciples

The Common reuse principle

Classes that are used together are packaged together

#PackageDesignPrinciples

#PackageDesignPrinciples

├── Core
│   ├── Authentication
│   ├── AuthenticationEvents.php
│   ├── Authorization
│   ├── Encoder
│   ├── Event
│   ├── Exception
│   ├── LICENSE
│   ├── README.md
│   ├── Resources
│   ├── Role
│   ├── Security.php
│   ├── Tests
│   ├── User
│   ├── Validator
│   ├── composer.json
│   └── phpunit.xml.dist
├── Csrf
│   ├── CsrfToken.php
│   ├── CsrfTokenManager.php
│   ├── CsrfTokenManagerInterface.php
│   ├── Exception
│   ├── LICENSE
│   ├── README.md
│   ├── Tests
│   ├── TokenGenerator
│   ├── TokenStorage
│   ├── composer.json
│   └── phpunit.xml.dist
├── Guard
│   ├── AbstractGuardAuthenticator.php
│   ├── Authenticator
│   ├── Firewall
│   ├── GuardAuthenticatorHandler.php
│   ├── GuardAuthenticatorInterface.php
│   ├── LICENSE
│   ├── Provider
│   ├── README.md
│   ├── Tests
│   ├── Token
│   ├── composer.json
│   └── phpunit.xml.dist
├── Http
│   ├── AccessMap.php
│   ├── AccessMapInterface.php
│   ├── Authentication
│   ├── Authorization
│   ├── EntryPoint
│   ├── Event
│   ├── Firewall
│   ├── Firewall.php
│   ├── FirewallMap.php
│   ├── FirewallMapInterface.php
│   ├── HttpUtils.php
│   ├── LICENSE
│   ├── Logout
│   ├── ParameterBagUtils.php
│   ├── README.md
│   ├── RememberMe
│   ├── SecurityEvents.php
│   ├── Session
│   ├── Tests
│   ├── Util
│   ├── composer.json
│   └── phpunit.xml.dist

#PackageDesignPrinciples

── Formatter
│   ├── ChromePHPFormatter.php
│   ├── ElasticaFormatter.php
│   ├── FlowdockFormatter.php
│   ├── FluentdFormatter.php
│   ├── FormatterInterface.php
│   ├── GelfMessageFormatter.php
│   ├── HtmlFormatter.php
│   ├── JsonFormatter.php
│   ├── LineFormatter.php
│   ├── LogglyFormatter.php
│   ├── LogmaticFormatter.php
│   ├── LogstashFormatter.php
│   ├── MongoDBFormatter.php
│   ├── NormalizerFormatter.php
│   ├── ScalarFormatter.php
│   └── WildfireFormatter.php
├── Handler
│   ├── AmqpHandler.php
│   ├── BrowserConsoleHandler.php
│   ├── ChromePHPHandler.php
│   ├── CouchDBHandler.php
│   ├── CubeHandler.php
│   ├── Curl
│   ├── DoctrineCouchDBHandler.php
│   ├── DynamoDbHandler.php
│   ├── ElasticSearchHandler.php
│   ├── ErrorLogHandler.php
│   ├── FilterHandler.php
│   ├── FingersCrossed
│   ├── FingersCrossedHandler.php
│   ├── FirePHPHandler.php
├── Processor
│   ├── GitProcessor.php
│   ├── IntrospectionProcessor.php
│   ├── MemoryPeakUsageProcessor.php
│   ├── MemoryProcessor.php
│   ├── MemoryUsageProcessor.php
│   ├── MercurialProcessor.php
│   ├── ProcessIdProcessor.php
│   ├── PsrLogMessageProcessor.php
│   ├── TagProcessor.php
│   ├── UidProcessor.php
│   └── WebProcessor.php

#PackageDesignPrinciples

    "require": {
        "php": "^7.0",
        "psr/log": "^1.0.1"
    },
    "suggest": {
        "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
        "sentry/sentry": "Allow sending log messages to a Sentry server",
        "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
        "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
        "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
        "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
        "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
        "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
        "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
        "rollbar/rollbar": "Allow sending log messages to Rollbar",
        "php-console/php-console": "Allow sending log messages to Google Chrome"
    },

#PackageDesignPrinciples

The Common closure principle

The classes that changed together are packaged together

#PackageDesignPrinciples

The classes in a package should be closed together against the same kind of changes.

#PackageDesignPrinciples

A change is likely to affect many classes of the package

#PackageDesignPrinciples

A change will affect only one package

#PackageDesignPrinciples

Ex: from mysql_ to PDO

A change in dependencies

#PackageDesignPrinciples

Ex: FOSUserBundle

A change in a layer

├── Command
├── Controller
├── DependencyInjection
├── Doctrine
├── Event
├── EventListener
├── Form
├── Mailer
├── Makefile
├── Model
├── Resources
├── Security
├── Tests
├── Util
├── Validator

#PackageDesignPrinciples

Ex: Sylius

A change in the business

SyliusAddressingBundle
SyliusCartBundle
SyliusFlowBundle
SyliusInventoryBundle
SyliusOmnipayBundle
SyliusOrderBundle
SyliusProductBundle
SyliusPromotionsBundle
SyliusResourceBundle
SyliusSettingsBundle
SyliusShippingBundle
SyliusTaxationBundle
SyliusTaxonomiesBundle
SyliusVariableProductBundle

#PackageDesignPrinciples

Coupling

How packages relate with one another

#PackageDesignPrinciples

The Acyclic dependencies principle

The dependency graph of packages must have no cycles

#PackageDesignPrinciples

A

B

C

D

A

B

C

D

Acyclic

Cyclic

#PackageDesignPrinciples


class Egg {
    public function __construct(Chicken $chicken) {}
}

class Chicken {
    public function __construct(Egg $egg) {}
}

#PackageDesignPrinciples

Form

FormInterface

Validator

ValidatorInterface

#PackageDesignPrinciples

Mediators

#PackageDesignPrinciples

The stable dependencies principle

Depend in the direction of stability

#PackageDesignPrinciples

A package should only depend upon packages that are
more stable than him

#PackageDesignPrinciples

1

0

Instability

I = 1

I = 0.5

I = 0

#PackageDesignPrinciples

1

0

Instability

I = 1

I = 0.5

I = 0

#PackageDesignPrinciples

FileSystem

1

0

Instability

knplabs/gaufrette

GaufretteFileSystemAdapter

viscaweb/gaufrette-filestystem-adapter

SomeClass

viscaweb/other-package

FileCopy

viscaweb/filesystem

FileSystemInterface

#PackageDesignPrinciples

The stable abstractions principle

Depend in the direction of abstractness

#PackageDesignPrinciples

A package stable should be abstract

A package instable should be concrete

Links

Uncle Bob
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Matthias Noback book
https://leanpub.com/principles-of-package-design

#PackageDesignPrinciples