IPC13 Munich: Planning the Unplannable

54
Planning for the unplannable

description

Long running projects, be it software or city planning, have something in common: the constant change to their environment. The problems to solve in one, two, or even five years from now will be different from those at hand now – and they are yet unknown. Thus dealing with uncertainty is one of the key issues and a well-planned architecture can help with that.

Transcript of IPC13 Munich: Planning the Unplannable

Page 1: IPC13 Munich: Planning the Unplannable

Planning for the unplannable

Page 2: IPC13 Munich: Planning the Unplannable

project founder of TYPO3 Flow and TYPO3 Neos

co-founder of the TYPO3 Association

software architect at TechDivision

37 years old

lives in Lübeck, Germany

1 wife, 2 daughters, 1 espresso machine

likes drumming

!

Page 3: IPC13 Munich: Planning the Unplannable

Experience

Page 4: IPC13 Munich: Planning the Unplannable

„Architecture”

Page 5: IPC13 Munich: Planning the Unplannable

Loose Coupling

Page 6: IPC13 Munich: Planning the Unplannable

High Cohesion

Page 7: IPC13 Munich: Planning the Unplannable

Law of Demeter

-each unit should have only limited knowledge about other units: only units "closely" related to the current unit.

-each unit should only talk to its friends; don't talk to strangers.

-only talk to your immediate friends.

Page 8: IPC13 Munich: Planning the Unplannable

Dependency Injection

Page 9: IPC13 Munich: Planning the Unplannable

<?php!class IsbnLookupService { protected static $instance; public function getInstance() { if (self::$instance === NULL) { self::$instance = new self; } return self::$instance; }}!!class BookSearchController { public function action() { $service = IsbnLookupService::getInstance(); … } }!

Page 10: IPC13 Munich: Planning the Unplannable

class ServiceLocator { protected static $services = array(); public function getInstance($name) { return self::$service[$name]; }!}!!class BookSearchService { public function action() { $service = ServiceLocater::getInstance("IsbnLookupService"); … } }

Page 11: IPC13 Munich: Planning the Unplannable

class BookSearchController extends ActionController {! /** * @var IsbnLookupService */ protected $isbnLookupService; /** * @param IsbnLookupService $isbnLookupService */ public function __construct(IsbnLookupService $service) { $this->isbnLookupService = $service; } }

Page 12: IPC13 Munich: Planning the Unplannable

class BookSearchController extends ActionController {! /** * @var IsbnLookupService */ protected $isbnLookupService; /** * @param IsbnLookupService $isbnLookupService */ public function injectLookupService(IsbnLookupService $service) { $this->isbnLookupService = $service; } }

Page 13: IPC13 Munich: Planning the Unplannable

class BookSearchController extends ActionController {! /** * @Flow\Inject * @var IsbnLookupService */ protected $isbnLookupService;!}

Page 14: IPC13 Munich: Planning the Unplannable

class BookSearchController extends ActionController {! /** * @Flow\Inject * @var IsbnLookupServiceInterface */ protected $isbnLookupService;!}

Page 15: IPC13 Munich: Planning the Unplannable

Acme\Controller\BookSearchController: properties: isbnLookupService: className: Amazon\Service\IsbnLookupService

Page 16: IPC13 Munich: Planning the Unplannable

Design Patterns

Page 17: IPC13 Munich: Planning the Unplannable
Page 18: IPC13 Munich: Planning the Unplannable

Reinvent the Wheel!

Page 19: IPC13 Munich: Planning the Unplannable

Planned and Unplanned Extensibility

Page 20: IPC13 Munich: Planning the Unplannable

Configuration

Page 21: IPC13 Munich: Planning the Unplannable
Page 22: IPC13 Munich: Planning the Unplannable

Signal-Slot Pattern

Page 23: IPC13 Munich: Planning the Unplannable
Page 24: IPC13 Munich: Planning the Unplannable
Page 25: IPC13 Munich: Planning the Unplannable

Observer, Dispatcher, Publish-Subsribe, Event-Notifier, …

Page 26: IPC13 Munich: Planning the Unplannable

Define a public API with @api

Page 27: IPC13 Munich: Planning the Unplannable

Code against interfaces

Page 28: IPC13 Munich: Planning the Unplannable

DI + Interfaces

Page 29: IPC13 Munich: Planning the Unplannable

AOP

Page 30: IPC13 Munich: Planning the Unplannable
Page 31: IPC13 Munich: Planning the Unplannable

Dependency Management: Composer, requirejs, …

Page 32: IPC13 Munich: Planning the Unplannable

Unit Tests

Page 33: IPC13 Munich: Planning the Unplannable

Functional Tests

Page 34: IPC13 Munich: Planning the Unplannable

System Tests

Page 35: IPC13 Munich: Planning the Unplannable
Page 36: IPC13 Munich: Planning the Unplannable
Page 37: IPC13 Munich: Planning the Unplannable

Understanding other’s code

Page 38: IPC13 Munich: Planning the Unplannable

Code Ownership

Page 39: IPC13 Munich: Planning the Unplannable

Software Rot

Page 40: IPC13 Munich: Planning the Unplannable

Remove unused code

Page 41: IPC13 Munich: Planning the Unplannable

Write code because it adds value (not because you can)

Page 42: IPC13 Munich: Planning the Unplannable

But maybe we need it (YAGNI)

Page 43: IPC13 Munich: Planning the Unplannable

Be canny with configuration

Page 44: IPC13 Munich: Planning the Unplannable

Reviews

Page 45: IPC13 Munich: Planning the Unplannable
Page 46: IPC13 Munich: Planning the Unplannable
Page 47: IPC13 Munich: Planning the Unplannable

Change your perspective

Page 48: IPC13 Munich: Planning the Unplannable

Be picky!Fix broken windows!

Page 49: IPC13 Munich: Planning the Unplannable

Readable Code

Page 50: IPC13 Munich: Planning the Unplannable

TYPO3 Flow Coding Guidelines on one page

<?phpnamespace Acme\TestPackage;

/* * * This script belongs to the TYPO3 Flow package "Acme.TestPackage". * * * * It is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License, either version 3 of the * * License, or (at your option) any later version. * * * * The TYPO3 project - inspiring people to share! * * */

use Acme\TestPackage\Service\FooGenerator;use TYPO3\Flow\Annotations as Flow;

/** * Here goes the description of the class. It should explain what the main * purpose of this class is... * * @Flow\Scope(”singleton”) */class UniverseAnalyzer extends BaseClass implements SomeInterface {

/** * Some injected dependency * * @Flow\Inject * @var FooGenerator */protected $someDependency = NULL;

/** * Shows if you are addicted to TYPO3 Flow * * @var boolean */static protected $addictedToFlow = TRUE;

/** * Shows if you are a fan of TYPO3 Flow * * @var boolean */protected $fanOfFlow;

/** * A great method which shows how to indent control structures. * * @param MyClass $object An instance of MyClass * @param array $someArray Some array * @return void * @throws \Exception */public function analyzeUniverse(MyClass $object, array $someArray = array()) {

$subObjects = $object->getSubObjects();foreach ($subObjects as $subObject){

/** @var $subObject MySubClass */$subObject->doSomethingCool();

}if (isset($someArray['question'])

&& $this->answerToEverything === 42|| count($someArray) > 3) {

$this->fanOfTYPO3Flow = TRUE;} else {

throw new \Exception('We cannot tolerate that.', 1223391710);}

}

/** * This is a setter for the fanOfFlow property. * * @param boolean $isFan Pass TRUE to mark a fan, FALSE for a Zend follower * @return mixed */public function setFanOfFlow($isFan) {

$this->fanOfFlow = $isFan;}

/** * As simple as it gets – a boolean getter. * * @return boolean Whether a foo was detected (TRUE) or not (FALSE) * @api */static public function isAddictedToFlow() {

return self::$addictedToFlow;}

}?>

Also check out the latest documentation: http://docs.typo3.org/flow/TYPO3FlowDocumentation/TheDefinitiveGuide/PartV/CodingGuideLines/Index.html

Description of the class. Make it as long as needed, feel free to explain how to use it.

Namespace starts with vendor name followed by package key (name) and subparts as needed

UpperCamelCase class name. Class names should be nouns.In other packages, import \Acme\TestPackage\UniverseAnalyzer and refer to it as UniverseAnalyer.

Opening brace on same line with opening token. One space before.

Use @var tag. Optional description goes in the first comment line followed by a blank comment line.

Indent with tabs.

Multiline conditions:Indent them and add a extra indent to following code. Put the boolean operators at beginning of line.

Write what went wrong, give helpful details and give a hint for a possible solution.

UNIX timestamp at time of writing the throw clause.

Description of the method. Make it as long as needed.

Use type hinting

Methods returning boolean values should start with “has” or “is”. Other getters should start with “get“.

Setter methods should start with “set”.

Method names should be verbs.

@return tag with type, even if it is “void”. Only __construct() has no return tag.

static and abstract keywords before the visibility modifier

@api tag defines public API

One use statement per line.One use statement per namespace.Order statements alphabetically.Don't import namespaces unless you use them.

No empty line between DocComment and class, member var or method.

Prefer relative namespaces, unless Fully Qualified Namespace is more readable

Param tag: type, name, description.

Only use inline @var annotations when type can't be derived (like in an array of objects) to increase readability and trigger IDE auto-completion.

List @Flow\* before other tags: @var, @param, @return, @throws, @api, @since, @deprecated

Capture the joy of coding as you create excellent web solutions.Enjoy coding. Enjoy Flow.

http://rlmk.me/flowcgl

Page 51: IPC13 Munich: Planning the Unplannable

Naming

Page 52: IPC13 Munich: Planning the Unplannable

! $path!! $pathAndFilename!! $filename!! $directory!! $directoryName!! $class!! $className

Page 53: IPC13 Munich: Planning the Unplannable

The pragmatic programmer Code complete All Martin Fowler Books (PoEAA)

Page 54: IPC13 Munich: Planning the Unplannable

@robertlemke

robertlemke.com