Planning for the Unplannable (IPC14 SE)

67
Planning for the Unplannable Framework-Grade Architecture Robert Lemke - TechDivision GmbH

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-chosen set of development techniques can help with that. Even if you don't plan to develop a framework, there's a lot you can learn from the development processes for creating your own stable and performant applications.

Transcript of Planning for the Unplannable (IPC14 SE)

Page 1: Planning for the Unplannable (IPC14 SE)

Planning for the Unplannable Framework-Grade Architecture

Robert Lemke - TechDivision GmbH

Page 2: Planning for the Unplannable (IPC14 SE)

TEXT HERE

Robert Lemke !

38 years old developer for 27 years lives in Lübeck, Germany software architect at TechDivision TYPO3 Association co-founder TYPO3 Flow & TYPO3 Neos project founder1 wife, 2 daughters, 1 espresso machine

Page 3: Planning for the Unplannable (IPC14 SE)

Framework-Grade?

Page 4: Planning for the Unplannable (IPC14 SE)

Architecture?

Page 5: Planning for the Unplannable (IPC14 SE)
Page 6: Planning for the Unplannable (IPC14 SE)

Image © Arquivo Nacional Brasil

Page 7: Planning for the Unplannable (IPC14 SE)

Image © 2014 Landsat / © 2014 GoogleImage © 2014 SIO, NOAA, U.S. Navy, NGA, GEBCO, Landsat, Google, Inav/Geosistemas SRL, Mapcity

Page 8: Planning for the Unplannable (IPC14 SE)
Page 9: Planning for the Unplannable (IPC14 SE)
Page 10: Planning for the Unplannable (IPC14 SE)
Page 11: Planning for the Unplannable (IPC14 SE)

TEXT HERE

Page 12: Planning for the Unplannable (IPC14 SE)

„this experiment was not successful”

Oscar Niemeyer 2001

Photo © Marcelo Coelho

Page 13: Planning for the Unplannable (IPC14 SE)

TEXT HERE

Page 14: Planning for the Unplannable (IPC14 SE)

If you know that you can’t planfor something, just

plan for the unplannable.

Page 15: Planning for the Unplannable (IPC14 SE)

Flexibility and quality are key

Page 16: Planning for the Unplannable (IPC14 SE)

Experience

Page 17: Planning for the Unplannable (IPC14 SE)

Design Patterns

Page 18: Planning for the Unplannable (IPC14 SE)
Page 19: Planning for the Unplannable (IPC14 SE)

Loose Coupling

Page 20: Planning for the Unplannable (IPC14 SE)

High Cohesion

Page 21: Planning for the Unplannable (IPC14 SE)

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 22: Planning for the Unplannable (IPC14 SE)

Code against interfaces

Page 23: Planning for the Unplannable (IPC14 SE)

Dependency Injection

Page 24: Planning for the Unplannable (IPC14 SE)

<?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 25: Planning for the Unplannable (IPC14 SE)

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

Page 26: Planning for the Unplannable (IPC14 SE)

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

Page 27: Planning for the Unplannable (IPC14 SE)

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

Page 28: Planning for the Unplannable (IPC14 SE)

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

Page 29: Planning for the Unplannable (IPC14 SE)

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

Page 30: Planning for the Unplannable (IPC14 SE)

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

Page 31: Planning for the Unplannable (IPC14 SE)

Planned and Unplanned Extensibility

Page 32: Planning for the Unplannable (IPC14 SE)

Configuration

Page 33: Planning for the Unplannable (IPC14 SE)
Page 34: Planning for the Unplannable (IPC14 SE)

Signal-Slot Pattern

Page 35: Planning for the Unplannable (IPC14 SE)
Page 36: Planning for the Unplannable (IPC14 SE)
Page 37: Planning for the Unplannable (IPC14 SE)

Observer, Dispatcher, Publish-Subscribe, Event-Notifier,

Event Sourcing …

Page 38: Planning for the Unplannable (IPC14 SE)

Define a public API with @api

Page 39: Planning for the Unplannable (IPC14 SE)

Aspect-Oriented Programming

Page 40: Planning for the Unplannable (IPC14 SE)
Page 41: Planning for the Unplannable (IPC14 SE)

Dependency Management: Composer, requirejs, …

Page 42: Planning for the Unplannable (IPC14 SE)

Reinvent the Wheel!

Page 43: Planning for the Unplannable (IPC14 SE)

Unit Tests

Page 44: Planning for the Unplannable (IPC14 SE)

Functional Tests

Page 45: Planning for the Unplannable (IPC14 SE)

System / Behavior Tests

Page 46: Planning for the Unplannable (IPC14 SE)
Page 47: Planning for the Unplannable (IPC14 SE)
Page 48: Planning for the Unplannable (IPC14 SE)

Understanding other people’s code

Page 49: Planning for the Unplannable (IPC14 SE)

Code Ownership

Page 50: Planning for the Unplannable (IPC14 SE)

Software Rot

Page 51: Planning for the Unplannable (IPC14 SE)

Be picky!Fix broken windows!

Page 52: Planning for the Unplannable (IPC14 SE)

Remove unused code

Page 53: Planning for the Unplannable (IPC14 SE)

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

Page 54: Planning for the Unplannable (IPC14 SE)

But maybe we need it (YAGNI)

Page 55: Planning for the Unplannable (IPC14 SE)

Be canny with configuration

Page 56: Planning for the Unplannable (IPC14 SE)

Reviews

Page 57: Planning for the Unplannable (IPC14 SE)
Page 58: Planning for the Unplannable (IPC14 SE)
Page 59: Planning for the Unplannable (IPC14 SE)

Change your perspective

Page 60: Planning for the Unplannable (IPC14 SE)

Readable Code

Page 61: Planning for the Unplannable (IPC14 SE)

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 62: Planning for the Unplannable (IPC14 SE)

Naming

Page 63: Planning for the Unplannable (IPC14 SE)

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

Page 64: Planning for the Unplannable (IPC14 SE)

© „davic” (Flickr)

Page 65: Planning for the Unplannable (IPC14 SE)

© „¡Carlitos” (Flickr)

Page 66: Planning for the Unplannable (IPC14 SE)

borrowed a lot from:

The pragmatic programmer Code complete

All Martin Fowler Books (PoEAA)

Page 67: Planning for the Unplannable (IPC14 SE)

TEXT HERE

@robertlemke !

robertlemke.com flow.typo3.org neos.typo3.org techdivision.com