Anzeige
Anzeige

Más contenido relacionado

Similar a Architecture in-the-small-slides(20)

Anzeige

Architecture in-the-small-slides

  1. Architecture in the Small 1 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  2. Hi! Vinai Kopp Freelance Developer and Trainer @VinaiKopp 2 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. Extraction & Encapsulation 8 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  9. Extraction? WTF? 9 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  10. A subset of Refactoring 10 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  13. The usual purpose of refactoring: Get rid of smelly code 13 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  14. But in case of extraction It can be more 14 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  15. Simplicity vs. Amount of code 15 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. 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. Tell, don't ask! 22 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  23. Extraction enables us to properly encapsulate functionality. 23 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. Managing State with Immutable Objects 26 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  27. Immutawhat? 27 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Yes, but... why? 29 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Reasonability 31 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  32. Reading ➡ Understanding 32 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  33. Understanding ➡ Knowing • Is it correct or • Is it incorrect 33 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Immutability helps to avoid temporal coupling 35 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  36. For Example: // MagentoBraintreeModelPaymentMethod::partialCapture() $this->config->initEnvironment($payment->getOrder()->getStoreId()); 36 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. 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. 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. External Initialization methods and Setters add complexity 44 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  45. External immutability & Internal immutability 45 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  46. Internal mutability allows for memoization 46 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. Testing code which uses immutable objects is simpler 50 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Yuck! 52 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. Once valid always valid Can something be „half valid“? 58 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. So how do the values get into an immutable object? 60 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  61. Constructor Injection 61 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Named constructor $request = HttpRequest::fromGlobalState(); 63 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. But IRL things change 66 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. Contraindications 69 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  70. Does immutability make code more complex or simple? 70 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. 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. 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. 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. 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. The Value of Validity 80 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  81. Enforce object validity at instantiation. 81 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Constructor validation The safest place to enforce validity 83 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. When it gets more complex... 85 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Each thing is a class Each object validates it's data 87 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. What about scalars? • string • int • bool • float • null • arrays of scalars 90 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Primitives Obsession No Type Safety (until PHP 7) Tests help 92 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  93. Primitives Obsession Easy to end up with Code Duplication 93 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. Primitives Obsession No built-in validation Tests help (again) 95 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  96. Benefits of scalar types 96 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  97. Benefits of scalar types They are immutable 97 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  98. Benefits of scalar types They are easily created 98 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  99. Benefits of scalar types They are comparable 99 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  100. Benefits of scalar types Serializable They work over the wire 100 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  101. Benefits of scalar types Completely upgrade safe 101 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  102. Benefits of scalar types They are fast 102 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  103. Benefits of scalar types They are language independent 103 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  104. Scalars vs. Value Objects 104 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  105. Scalars make great boundary interfaces 105 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  106. Scalar Boundary Interfaces • Web API • Components API • Message Queue Payload 106 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. Immutable Variables 109 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  110. In PHP? No 110 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  111. But we can treat variables as immutable. 111 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. Immutable Variables ++Reasonability 117 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  118. Immutable Variables Less bugs 118 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  119. Immutable Variables Simple to refactor 119 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. Reasoning about Code with Idempotence 122 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  123. Another of those words... 123 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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. 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. Pure Functions All pure functions are idempotent 129 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  130. Pure Functions No side effects 130 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  131. Pure Functions Rely only on input arguments 131 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. And my point is? 134 Architecture in the Small - MageTitans 2015 - ! - @VinaiKopp - contact@vinaikopp.com - © 2015
  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. 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. 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. 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
Anzeige