Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Architecture
in the Small
1 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Hi!
Vinai Kopp
Freelance Developer and Trainer
@VinaiKopp
2 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp -...
My PHP Evolution:
1. Quick Hacks (1999)
2. Typo3 Plugin Developer (2003)
3. Magento Developer (2008)
4. Experienced Magent...
I hope some of the following
will be useful and interesting
to play with for you, too
4 Architecture in the Small - MageTi...
Some of the many People
who inspired and helped me
• Rich Hickey
• Robert C. Martin
• Martin Fowler
• Kent Beck
All brilli...
Disclaimer
The following thoughts are all mine, but influenced by
reading these great peoples work.
If I get something wro...
Topics
• Extraction & Encapsulation
• Managing State with Immutable Objects
• The Value of Validity
• Immutable Variables
...
Extraction
&
Encapsulation
8 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Extraction?
WTF?
9 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
A subset of
Refactoring
10 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
„Refactoring is the process of changing a software
system in such a way that it does not alter the external
behavior of th...
12 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
The usual purpose of refactoring:
Get rid of smelly code
13 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp -...
But in case of extraction
It can be more
14 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaiko...
Simplicity
vs.
Amount of code
15 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © ...
Simplicity
Can make things
visible
that where hidden in the code
16 Architecture in the Small - MageTitans 2015 - ! - @Vin...
Extract Method Example - Before
// MagentoCatalogModelProduct
protected function convertToMediaGalleryInterface(array $med...
Extract Method Example - After (1/2)
// MagentoCatalogModelProduct
protected function convertToMediaGalleryInterface(array...
Extract Method Example - After (2/2)
// MagentoCatalogModelProduct
protected function convertToMediaGalleryInterface(array...
Encapsulation
„In general, encapsulation is the inclusion of one thing
within another thing so that the included thing is ...
Encapsulation
„Other objects ... use the object without having to be
concerned with how the object accomplishes it.“
-- Te...
Tell, don't ask!
22 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Extraction enables us to properly encapsulate
functionality.
23 Architecture in the Small - MageTitans 2015 - ! - @VinaiKo...
Proposition:
It is good to write code that is simple to extract.
24 Architecture in the Small - MageTitans 2015 - ! - @Vin...
Topics
• Extraction & Encapsulation
• Managing State with Immutable Objects
• The Value of Validity
• Immutable Variables
...
Managing State
with Immutable
Objects
26 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp....
Immutawhat?
27 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
„In object-oriented and functional programming, an
immutable object is an object whose state cannot be
modified after it i...
Yes, but... why?
29 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
I've read it helps avoid a whole class of bugs.
So, what are they?
30 Architecture in the Small - MageTitans 2015 - ! - @V...
Reasonability
31 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Reading ➡ Understanding
32 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Understanding ➡ Knowing
• Is it correct
or
• Is it incorrect
33 Architecture in the Small - MageTitans 2015 - ! - @VinaiKo...
When objects change in distant code, it becomes more
complex to track what changed where and why.
34 Architecture in the S...
Immutability helps to avoid
temporal coupling
35 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vi...
For Example:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrder()->g...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
Temporal Coupling:
// MagentoBraintreeModelPaymentMethod::partialCapture()
$this->config->initEnvironment($payment->getOrde...
External
Initialization methods
and
Setters
add complexity
44 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp...
External immutability
&
Internal immutability
45 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vi...
Internal mutability allows for memoization
46 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinai...
Memoization :
„An optimization technique to speed up expensive
method calls by storing the result after the first call and...
Memoization Example
public function getAltitudeAvg(Location $loc, Date $date)
{
$coords = (string) $loc->getCoords();
$dat...
Anyway...
Memoization is a lot simpler to do with
externally immutable objects
since nothing can invalidate the result.
49...
Testing code which uses
immutable objects is simpler
50 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - con...
Test Double: Mutable Object
$initWasCalled = false;
$mockConfig = $this->getMock(MagentoBraintreeModelConfig, [], [], '', fa...
Yuck!
52 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Incomplete Test Double:
Mutable Object
$initializedConfigMock = $this->getMock(MagentoBraintreeModelConfig, [], [], '', fals...
Test Double: Immutable Object
$configMock = $this->getMock(MagentoBraintreeModelConfig, [], [], '', false);
$configMock->meth...
Simpler to cache
No need to worry that an object changes after it is
written to cache.
55 Architecture in the Small - Mage...
Example:
Magento EE PageCache
<controller_front_send_response_before>
<observers>
<enterprise_pagecache>
<class>enterprise...
Example:
Magento EE PageCache
Events after cache write:
• controller_front_send_response_before
(in a later Observer)
• co...
Once valid
always valid
Can something be „half valid“?
58 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - c...
Example: invalidation of a mutable object
$product = $productCollection->getFirstItem();
$product->getPrice(); // 24.99
$p...
So how do the values get into an immutable object?
60 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - conta...
Constructor Injection
61 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
__construct()
$request = new HttpRequest(
HttpRequest::METHOD_GET,
HttpUrl::fromString('http://example.com/lookie/here'),
...
Named constructor
$request = HttpRequest::fromGlobalState();
63 Architecture in the Small - MageTitans 2015 - ! - @VinaiKo...
Example 1: named constructor
public static function fromGlobalState($requestBody = '')
{
$method = $_SERVER['REQUEST_METHO...
Example 2: named constructor
public static function fromScalars(
$methodString,
$urlString,
$headersArray,
$bodyString
) {...
But IRL
things change
66 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Modeling change with
immutable objects
Change is introduced by creating a new instance.
67 Architecture in the Small - Mag...
Looks like mutation, but it ain't
$today = new DateTimeImmutable();
echo $today->format('Y-m-d H:i:s'); // 2015-10-29 21:3...
Contraindications
69 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Does immutability make code more
complex
or
simple?
70 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - cont...
A thing that changes over time.
$room = new ConferenceRoom(
$location,
$event,
$attendees
)
71 Architecture in the Small -...
Is it a new conference room just because the number of
people change?
72 Architecture in the Small - MageTitans 2015 - ! -...
A mutable conference room model:
$nPeople = $room->countPeople();
$room->addPerson($attendee);
$room->countPeople() === $n...
A immutable conference room model:
$nPeople = $room->countPeople();
$updatedRoom = $room->addPerson($attendee);
$room->cou...
Temporal modeling
An instance represents the object
at one moment in time.
75 Architecture in the Small - MageTitans 2015 ...
Temporal modeling
(Immutable object at a moment in time)
(Immutable object at a moment in time)
(Immutable object at a mom...
Temporal modeling
Keeps History !
Not a natural way to do OOP, adds complexity !
Unaccustomed way to think ! "
77 Architec...
Bottom Line
If you don't have to model changes over time, using
immutability will probably make your code simpler.
If you ...
Topics
• Extraction & Encapsulation
• Managing State with Immutable Objects
• The Value of Validity
• Immutable Variables
...
The Value of
Validity
80 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Enforce object validity at instantiation.
81 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaik...
Validation at Instantiation
• __construct()
• Named constructor (aka Factory Method)
• Builder or Factory
82 Architecture ...
Constructor validation
The safest place to enforce validity
83 Architecture in the Small - MageTitans 2015 - ! - @VinaiKop...
Example Constructor Validation
public function __construct($amount)
{
if (!is_int($amount)) {
$type = gettype($amount);
$m...
When it gets more complex...
85 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2...
Example Delegation of Validation
// ProductAttributeListBuilder
public static function fromArray(array $attributesArray)
{...
Each thing is a class
Each object validates it's data
87 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - co...
Plug: Value Objects
Introduction slides on Value Objects
by Tim Bezhashvyly
http://vin.ai/tims_value_objects
88 Architectu...
The cost of validity
Classes require time to write, test and maintain.
• Each thing is a new class
• Lots of code
89 Archi...
What about scalars?
• string
• int
• bool
• float
• null
• arrays of scalars
90 Architecture in the Small - MageTitans 201...
Code Smell:
Primitives Obsession
„Primitives Obsession is using primitive data types to
represent domain ideas.“
91 Archit...
Primitives Obsession
No Type Safety
(until PHP 7)
Tests help
92 Architecture in the Small - MageTitans 2015 - ! - @VinaiKo...
Primitives Obsession
Easy to end up with Code Duplication
93 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp ...
Primitives Obsession
Magic values
„I knew at once what process(1.34, true) meant!“
-- Noone, ever
Class names have documen...
Primitives Obsession
No built-in validation
Tests help (again)
95 Architecture in the Small - MageTitans 2015 - ! - @Vinai...
Benefits of scalar types
96 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Benefits of scalar types
They are immutable
97 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vina...
Benefits of scalar types
They are easily created
98 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact...
Benefits of scalar types
They are comparable
99 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vin...
Benefits of scalar types
Serializable
They work over the wire
100 Architecture in the Small - MageTitans 2015 - ! - @Vinai...
Benefits of scalar types
Completely upgrade safe
101 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contac...
Benefits of scalar types
They are fast
102 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikop...
Benefits of scalar types
They are language independent
103 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - ...
Scalars
vs.
Value Objects
104 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Scalars make great
boundary interfaces
105 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikop...
Scalar Boundary Interfaces
• Web API
• Components API
• Message Queue Payload
106 Architecture in the Small - MageTitans 2...
Scalar Boundary Interfaces
• Less interface dependencies
• But implicit coupling to data format
107 Architecture in the Sm...
Topics
• Extraction & Encapsulation
• Managing State with Immutable Objects
• The Value of Validity
• Immutable Variables
...
Immutable Variables
109 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
In PHP?
No
110 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
But we can treat variables as immutable.
111 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaik...
Example 1: reusing local variables
public function testTwoRequestsAddTwoMessages()
{
$request = $this->createProductUpdate...
What is the problem?
• Messy to move or extract
• Complex to reason about
113 Architecture in the Small - MageTitans 2015 ...
Example 1: treating local variables as immutable
public function testTwoRequestsAddTwoMessages()
{
$productUpdateRequest =...
Example 2: local variable mutation in a loop
// MagentoCatalogModelProduct
protected function convertToMediaGalleryInterfa...
Example 2: map/reduce helps avoiding local variable
mutation
// MagentoCatalogModelProduct
protected function convertToMed...
Immutable Variables
++Reasonability
117 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.c...
Immutable Variables
Less bugs
118 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - ©...
Immutable Variables
Simple to refactor
119 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikop...
Immutable Variables
My new friends:
• Closure
• array_map()
• array_reduce()
• array_merge()
• array_filter()
• recursion
...
Topics
• Extraction & Encapsulation
• Managing State with Immutable Objects
• The Value of Validity
• Immutable Variables
...
Reasoning about
Code with
Idempotence
122 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp...
Another of those words...
123 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Idempotence
„In computer science, the term idempotent is used ... to
describe an operation that will produce the same
resu...
What it ain't
Example 1
class Logger
{
public function log($level, $message)
{
$f = fopen($this->file . '-' . $level, 'a');...
Idempotent logger
Example 1
class Logger
{
public function log($level, $message)
{
$f = fopen($this->file . '-' . $level, '...
What it ain't
Example 2
protected function validateIsFoo($object)
{
if (! $object instanceof Foo) {
echo "$object is not a...
Idempotent validateIsFoo
Example 2
protected function validateIsFoo($object)
{
return $object instanceof Foo;
}
// no outp...
Pure Functions
All pure functions are idempotent
129 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contac...
Pure Functions
No side effects
130 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - ...
Pure Functions
Rely only on input arguments
131 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vin...
Pure Functions
No dependency on global state such as
• $_SERVER, $_SESSION
• getcwd()
• file_exists()
• Mage::getIsDevelop...
Pure Functions
For the same input they always return the same output
133 Architecture in the Small - MageTitans 2015 - ! -...
And my point is?
134 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
Idempotent Functions are
Simpler to reuse
Simpler to compose
Pure Functions are
Simpler to refactor
Simpler to change
Simp...
It pays to focus on the
dependencies of every
method
OOP is all about dependency management
136 Architecture in the Small ...
I'm still learning
But so far results are very encouraging.
I'm happy for every tool that helps to reduce complexity
137 A...
Thanks for your attention!
Please,
Ask questions, and
I'm eager to hear your thoughts and comments!
138 Architecture in th...
Upcoming SlideShare
Loading in …5
×

Architecture in-the-small-slides

6,623 views

Published on

Creating software requires from us developers to make a constant stream of choices.
Each of the choices we make hopefully brings the software we are writing closer to the state of functionality it is required to have.
At the same time, each of the choices we make forms the code in a way that impacts how we can continue to work with it, how easy it is to expand and build on to, how simple it is to understand, and how many bugs we will allow to creep in.
In short, the choices we make impact the cost of development.
This talk is about development guidelines for those choices that allow us to save time and money.
Contradicting the intuitive conclusion that this means cutting corners, it actually means that we have to focus on creating programs with a high external and internal quality; that clean code pays off.

Published in: Software

Architecture in-the-small-slides

  1. 1. Architecture in the Small 1 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  2. 2. Hi! Vinai Kopp Freelance Developer and Trainer @VinaiKopp 2 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  3. 3. My PHP Evolution: 1. Quick Hacks (1999) 2. Typo3 Plugin Developer (2003) 3. Magento Developer (2008) 4. Experienced Magento Developer (2012) 5. Discovering Code Beyond Magento (2014) 3 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  4. 4. I hope some of the following will be useful and interesting to play with for you, too 4 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  5. 5. Some of the many People who inspired and helped me • Rich Hickey • Robert C. Martin • Martin Fowler • Kent Beck All brilliant people with a sense of humor! 5 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  6. 6. Disclaimer The following thoughts are all mine, but influenced by reading these great peoples work. If I get something wrong, it is all my fault. I might change my mind about something at any time. 6 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  7. 7. Topics • Extraction & Encapsulation • Managing State with Immutable Objects • The Value of Validity • Immutable Variables • Reasoning about Code with Idempotence 7 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  8. 8. Extraction & Encapsulation 8 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  9. 9. Extraction? WTF? 9 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  10. 10. A subset of Refactoring 10 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  11. 11. „Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure“ -- Martin Fowler, Refactoring (Addison-Wesley) 11 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  12. 12. 12 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  13. 13. The usual purpose of refactoring: Get rid of smelly code 13 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  14. 14. But in case of extraction It can be more 14 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  15. 15. Simplicity vs. Amount of code 15 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  16. 16. Simplicity Can make things visible that where hidden in the code 16 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  17. 17. Extract Method Example - Before // MagentoCatalogModelProduct protected function convertToMediaGalleryInterface(array $mediaGallery) { $entries = []; foreach ($mediaGallery as $image) { $entry = $this ->mediaGalleryEntryConverterPool ->getConverterByMediaType($image['media_type']) ->convertTo($this, $image); $entries[] = $entry; } return $entries; } 17 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  18. 18. Extract Method Example - After (1/2) // MagentoCatalogModelProduct protected function convertToMediaGalleryInterface(array $mediaGallery) { $entries = []; foreach ($mediaGallery as $image) { $entries[] = $this->convertImageToMediaGalleryEntry($image); } return $entries; } private function convertImageToMediaGalleryEntry(array $image) { $converter = $this->mediaGalleryEntryConverterPool ->getConverterByMediaType($image['media_type']); return $converter->convertTo($this, $image); } 18 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  19. 19. Extract Method Example - After (2/2) // MagentoCatalogModelProduct protected function convertToMediaGalleryInterface(array $mediaGallery) { $entries = []; foreach ($mediaGallery as $image) { $entries[] = $this->mediaGalleryEntryConverterPool ->convertImageToMediaGalleryEntry($image, $this); } return $entries; } // MagentoCatalogModelProductAttributeBackendMediaEntryConverterPool public function convertImageToMediaGalleryEntry(array $image, Product $product) { $converter = $this->getConverterByMediaType($image['media_type']); return $converter->convertTo($product, $image); } 19 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  20. 20. Encapsulation „In general, encapsulation is the inclusion of one thing within another thing so that the included thing is not apparent.“ -- TechTarget SearchNetworking 20 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  21. 21. Encapsulation „Other objects ... use the object without having to be concerned with how the object accomplishes it.“ -- TechTarget SearchNetworking 21 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  22. 22. Tell, don't ask! 22 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  23. 23. Extraction enables us to properly encapsulate functionality. 23 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  24. 24. Proposition: It is good to write code that is simple to extract. 24 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  25. 25. Topics • Extraction & Encapsulation • Managing State with Immutable Objects • The Value of Validity • Immutable Variables • Reasoning about Code with Idempotence 25 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  26. 26. Managing State with Immutable Objects 26 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  27. 27. Immutawhat? 27 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  28. 28. „In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created.“ -- Wikipedia, Immutable object 28 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  29. 29. Yes, but... why? 29 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  30. 30. I've read it helps avoid a whole class of bugs. So, what are they? 30 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  31. 31. Reasonability 31 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  32. 32. Reading ➡ Understanding 32 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  33. 33. Understanding ➡ Knowing • Is it correct or • Is it incorrect 33 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  34. 34. When objects change in distant code, it becomes more complex to track what changed where and why. 34 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  35. 35. Immutability helps to avoid temporal coupling 35 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  36. 36. For Example: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); 36 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  37. 37. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What state does the config start out in before it is initialized? 37 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  38. 38. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What happens if the config is initialized twice with different store ids? 38 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  39. 39. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What happens if another method is called before this one and the other one also relies on the config environment being initialized? 39 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  40. 40. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What happens if the call to initEnvironment is missed? 40 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  41. 41. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); Extracting methods is tricky because the extracted part might rely on a different method being called first. This might not be apparent. 41 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  42. 42. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What happens if another object has a reference to the same config instance, but it doesn't know about or expect the config change? 42 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  43. 43. Temporal Coupling: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); What happens if a response of the payment instance is cached and then the config environment is changed? 43 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  44. 44. External Initialization methods and Setters add complexity 44 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  45. 45. External immutability & Internal immutability 45 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  46. 46. Internal mutability allows for memoization 46 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  47. 47. Memoization : „An optimization technique to speed up expensive method calls by storing the result after the first call and returning the cached result if the same inputs occur again.“ 47 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  48. 48. Memoization Example public function getAltitudeAvg(Location $loc, Date $date) { $coords = (string) $loc->getCoords(); $dateStr = (string) $date; if (! @$this->memoizedResults[$coords][$dateStr]) { $avgAltitude = $this->doExpensiveCalculation($loc, $date); $this->memoizedResults[$coords][$dateStr] = $avgAltitude; } return $this->memoizedResults[$coords][$dateStr]; } 48 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  49. 49. Anyway... Memoization is a lot simpler to do with externally immutable objects since nothing can invalidate the result. 49 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  50. 50. Testing code which uses immutable objects is simpler 50 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  51. 51. Test Double: Mutable Object $initWasCalled = false; $mockConfig = $this->getMock(MagentoBraintreeModelConfig, [], [], '', false); $mockConfig->method('initEnvironment') ->willReturnCallback(function () use (&$initWasCalled) { $initWasCalled = true; }); $mockConfig->method('canUseForCountry') ->willReturnCallback(function ($country) use (&$initWasCalled) { return $initWasCalled ? false : true; }); 51 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  52. 52. Yuck! 52 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  53. 53. Incomplete Test Double: Mutable Object $initializedConfigMock = $this->getMock(MagentoBraintreeModelConfig, [], [], '', false); $initializedConfigMock->method('canUseForCountry')->willReturn(true); Easy to miss calling initEnvironment in the system under test! 53 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  54. 54. Test Double: Immutable Object $configMock = $this->getMock(MagentoBraintreeModelConfig, [], [], '', false); $configMock->method('canUseForCountry')->willReturn(true); 54 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  55. 55. Simpler to cache No need to worry that an object changes after it is written to cache. 55 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  56. 56. Example: Magento EE PageCache <controller_front_send_response_before> <observers> <enterprise_pagecache> <class>enterprise_pagecache/observer</class> <method>cacheResponse</method> </enterprise_pagecache> </observers> </controller_front_send_response_before> 56 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  57. 57. Example: Magento EE PageCache Events after cache write: • controller_front_send_response_before (in a later Observer) • controller_front_send_response_after • http_response_send_before 57 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  58. 58. Once valid always valid Can something be „half valid“? 58 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  59. 59. Example: invalidation of a mutable object $product = $productCollection->getFirstItem(); $product->getPrice(); // 24.99 $product->getSpecialPrice(); // 19.99 $product->setPrice(11.95); $product->setSpecialPrice(10.95); $product->getFinalPrice() // 19.99 59 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  60. 60. So how do the values get into an immutable object? 60 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  61. 61. Constructor Injection 61 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  62. 62. __construct() $request = new HttpRequest( HttpRequest::METHOD_GET, HttpUrl::fromString('http://example.com/lookie/here'), HttpHeaders::fromArray($httpHeaders), HttpRequestBody::fromString($httpRequestBodyString) ); 62 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  63. 63. Named constructor $request = HttpRequest::fromGlobalState(); 63 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  64. 64. Example 1: named constructor public static function fromGlobalState($requestBody = '') { $method = $_SERVER['REQUEST_METHOD']; $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) ? 'https' : 'http'; $path = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $url = $protocol . '://' . $path; $headers = self::getGlobalRequestHeaders(); return static::fromScalars($method, $url, $headers, $requestBody); } 64 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  65. 65. Example 2: named constructor public static function fromScalars( $methodString, $urlString, $headersArray, $bodyString ) { $url = HttpUrl::fromString($urlString); $headers = HttpHeaders::fromArray($headersArray); $body = HttpRequestBody::fromString($bodyString); return new self($methodString, $url, $headers, $body); } 65 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  66. 66. But IRL things change 66 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  67. 67. Modeling change with immutable objects Change is introduced by creating a new instance. 67 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  68. 68. Looks like mutation, but it ain't $today = new DateTimeImmutable(); echo $today->format('Y-m-d H:i:s'); // 2015-10-29 21:32:06 $day = DateInterval::createFromDateString('24 hours'); $tomorrow = $today->add($day); echo $today->format('Y-m-d H:i:s'); // 2015-10-29 21:32:06 echo $tomorrow->format('Y-m-d H:i:s');// 2015-10-30 21:32:06 68 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  69. 69. Contraindications 69 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  70. 70. Does immutability make code more complex or simple? 70 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  71. 71. A thing that changes over time. $room = new ConferenceRoom( $location, $event, $attendees ) 71 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  72. 72. Is it a new conference room just because the number of people change? 72 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  73. 73. A mutable conference room model: $nPeople = $room->countPeople(); $room->addPerson($attendee); $room->countPeople() === $nPeople + 1; 73 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  74. 74. A immutable conference room model: $nPeople = $room->countPeople(); $updatedRoom = $room->addPerson($attendee); $room->countPeople() === $nPeople; $updatedRoom->countPeople() === $nPeople + 1; 74 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  75. 75. Temporal modeling An instance represents the object at one moment in time. 75 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  76. 76. Temporal modeling (Immutable object at a moment in time) (Immutable object at a moment in time) (Immutable object at a moment in time) (Immutable object at a moment in time) ... All the same Entity that changes over time. 76 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  77. 77. Temporal modeling Keeps History ! Not a natural way to do OOP, adds complexity ! Unaccustomed way to think ! " 77 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  78. 78. Bottom Line If you don't have to model changes over time, using immutability will probably make your code simpler. If you do have to worry about changes over time... it depends. 78 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  79. 79. Topics • Extraction & Encapsulation • Managing State with Immutable Objects • The Value of Validity • Immutable Variables • Reasoning about Code with Idempotence 79 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  80. 80. The Value of Validity 80 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  81. 81. Enforce object validity at instantiation. 81 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  82. 82. Validation at Instantiation • __construct() • Named constructor (aka Factory Method) • Builder or Factory 82 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  83. 83. Constructor validation The safest place to enforce validity 83 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  84. 84. Example Constructor Validation public function __construct($amount) { if (!is_int($amount)) { $type = gettype($amount); $msg = sprintf('Can not create price from "%s"', $type); throw new InvalidAmountTypeException($msg); } $this->amount = $amount; } 84 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  85. 85. When it gets more complex... 85 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  86. 86. Example Delegation of Validation // ProductAttributeListBuilder public static function fromArray(array $attributesArray) { $attributes = array_map(function (array $attributeArray) { return ProductAttribute::fromArray($attributeArray); }, $attributesArray); return new self(...$attributes); } public function __construct(ProductAttribute ...$attributes) { $this->validateAllAttributesHaveCompatibleContextData(...$attributes); $this->attributes = $attributes; } 86 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  87. 87. Each thing is a class Each object validates it's data 87 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  88. 88. Plug: Value Objects Introduction slides on Value Objects by Tim Bezhashvyly http://vin.ai/tims_value_objects 88 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  89. 89. The cost of validity Classes require time to write, test and maintain. • Each thing is a new class • Lots of code 89 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  90. 90. What about scalars? • string • int • bool • float • null • arrays of scalars 90 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  91. 91. Code Smell: Primitives Obsession „Primitives Obsession is using primitive data types to represent domain ideas.“ 91 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  92. 92. Primitives Obsession No Type Safety (until PHP 7) Tests help 92 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  93. 93. Primitives Obsession Easy to end up with Code Duplication 93 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  94. 94. Primitives Obsession Magic values „I knew at once what process(1.34, true) meant!“ -- Noone, ever Class names have documentary value 94 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  95. 95. Primitives Obsession No built-in validation Tests help (again) 95 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  96. 96. Benefits of scalar types 96 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  97. 97. Benefits of scalar types They are immutable 97 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  98. 98. Benefits of scalar types They are easily created 98 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  99. 99. Benefits of scalar types They are comparable 99 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  100. 100. Benefits of scalar types Serializable They work over the wire 100 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  101. 101. Benefits of scalar types Completely upgrade safe 101 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  102. 102. Benefits of scalar types They are fast 102 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  103. 103. Benefits of scalar types They are language independent 103 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  104. 104. Scalars vs. Value Objects 104 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  105. 105. Scalars make great boundary interfaces 105 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  106. 106. Scalar Boundary Interfaces • Web API • Components API • Message Queue Payload 106 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  107. 107. Scalar Boundary Interfaces • Less interface dependencies • But implicit coupling to data format 107 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  108. 108. Topics • Extraction & Encapsulation • Managing State with Immutable Objects • The Value of Validity • Immutable Variables • Reasoning about Code with Idempotence 108 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  109. 109. Immutable Variables 109 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  110. 110. In PHP? No 110 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  111. 111. But we can treat variables as immutable. 111 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  112. 112. Example 1: reusing local variables public function testTwoRequestsAddTwoMessages() { $request = $this->createProductUpdateRequest(); $app = new WebFront($request, $this->testFactory); $app->runWithoutSendingResponse(); $request = $this->createStockUpdateRequest(); $app = new WebFront($request, $this->testFactory); $app->runWithoutSendingResponse(); $queue = $this->testFactory->createQueue(); $this->assertCount(2, $queue); } // Multiple assignments to $request and $app 112 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  113. 113. What is the problem? • Messy to move or extract • Complex to reason about 113 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  114. 114. Example 1: treating local variables as immutable public function testTwoRequestsAddTwoMessages() { $productUpdateRequest = $this->createProductUpdateRequest(); $firstApp = new WebFront($productUpdateRequest, $this->testFactory); $firstApp->runWithoutSendingResponse(); $stockUpdateRequest = $this->createStockUpdateRequest(); $secondApp = new WebFront($stockUpdateRequest, $this->testFactory); $secondApp->runWithoutSendingResponse(); $queue = $this->testFactory->createQueue(); $this->assertCount(2, $queue); } 114 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  115. 115. Example 2: local variable mutation in a loop // MagentoCatalogModelProduct protected function convertToMediaGalleryInterface(array $mediaGallery) { $entries = []; foreach ($mediaGallery as $image) { $entries[] = $this->mediaGalleryEntryConverterPool ->convertImageToMediaGalleryEntry($image, $this); } return $entries; } // Multiple assignments to $image, mutation of $entries 115 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  116. 116. Example 2: map/reduce helps avoiding local variable mutation // MagentoCatalogModelProduct protected function convertToMediaGalleryInterface(array $mediaGallery) { return array_map( function ($image) { $this->mediaGalleryEntryConverterPool ->convertImageToMediaGalleryEntry($image, $this); }, $mediaGallery ); } 116 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  117. 117. Immutable Variables ++Reasonability 117 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  118. 118. Immutable Variables Less bugs 118 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  119. 119. Immutable Variables Simple to refactor 119 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  120. 120. Immutable Variables My new friends: • Closure • array_map() • array_reduce() • array_merge() • array_filter() • recursion • ... 120 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  121. 121. Topics • Extraction & Encapsulation • Managing State with Immutable Objects • The Value of Validity • Immutable Variables • Reasoning about Code with Idempotence 121 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  122. 122. Reasoning about Code with Idempotence 122 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  123. 123. Another of those words... 123 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  124. 124. Idempotence „In computer science, the term idempotent is used ... to describe an operation that will produce the same results if executed once or multiple times.“ -- Wikipedia, Idempotence, Computer Science 124 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  125. 125. What it ain't Example 1 class Logger { public function log($level, $message) { $f = fopen($this->file . '-' . $level, 'a'); flock($f, LOCK_EX); fwrite($f, message); flock($f, LOCK_UN); fclose($f); } } // repeated calls add additional records 125 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  126. 126. Idempotent logger Example 1 class Logger { public function log($level, $message) { $f = fopen($this->file . '-' . $level, 'a'); flock($f, LOCK_EX); if ($this->getLastLineFromFile() !== $message) { fwrite($f, message); } flock($f, LOCK_UN); fclose($f); } } // repeated calls add NO additional records 126 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  127. 127. What it ain't Example 2 protected function validateIsFoo($object) { if (! $object instanceof Foo) { echo "$object is not an instance of Foon"; return false; } return true; } // repeated calls may produce repeated output 127 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  128. 128. Idempotent validateIsFoo Example 2 protected function validateIsFoo($object) { return $object instanceof Foo; } // no output 128 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  129. 129. Pure Functions All pure functions are idempotent 129 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  130. 130. Pure Functions No side effects 130 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  131. 131. Pure Functions Rely only on input arguments 131 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  132. 132. Pure Functions No dependency on global state such as • $_SERVER, $_SESSION • getcwd() • file_exists() • Mage::getIsDeveloperMode() 132 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  133. 133. Pure Functions For the same input they always return the same output 133 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  134. 134. And my point is? 134 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  135. 135. Idempotent Functions are Simpler to reuse Simpler to compose Pure Functions are Simpler to refactor Simpler to change Simpler to reason about 135 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  136. 136. It pays to focus on the dependencies of every method OOP is all about dependency management 136 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  137. 137. I'm still learning But so far results are very encouraging. I'm happy for every tool that helps to reduce complexity 137 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  138. 138. Thanks for your attention! Please, Ask questions, and I'm eager to hear your thoughts and comments! 138 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015

×