From framework coupled code to #microservices through #DDD /by @codelytv

50
From framework coupled code to microservices through DDD modules MVC, Testing, SOLID, Domain-Driven Design, Microservices @CodelyTV @Rafaoe @JavierCane #NubeloMeetup - IronHack 25/10/2016

Transcript of From framework coupled code to #microservices through #DDD /by @codelytv

From framework coupled code to microservices through DDD modules MVC, Testing, SOLID, Domain-Driven Design, Microservices

@CodelyTV @Rafaoe

@JavierCane#NubeloMeetup - IronHack 25/10/2016

Venue

Org

Beers

Contents

Welcome!

@Rafaoe @JavierCane

Contents

gOld days The holy grail of testing

Bigger & faster

MVC frameworks to the rescue

Serious business Recap

Thanks!

@TangeloEng@UvinumEng@Thatzad

1.gOLD days

<?php/** * The template for displaying all single posts and attachments * * @package WordPress * @subpackage Twenty_Sixteen * @since Twenty Sixteen 1.0 */get_header(); ?> <div id="primary" class="content-area"> <main id="main" class="site-main" role="main"> <?php // Start the loop. while (have_posts()) : the_post();

single.php

role="main"> <?php // Start the loop. while (have_posts()) : the_post(); // Include the single post content template. get_template_part('template-parts/content', 'single'); // If comments are open or we have at least one comment, load up the comment template. if (comments_open() || get_comments_number()) { comments_template(); } if (is_singular('attachment')) { // Parent post navigation.

single.php

'twentysixteen' ) . '</span> ' . '<span class="post-title">%title</span>', ] ); } // End of the loop. endwhile; ?> </main><!-- .site-main --> <?php get_sidebar('content-bottom'); ?> </div><!-- .content-area --><?php get_sidebar(); ?><?php get_footer(); ?>

single.php

● Scripts

◕ index.php

◕ utils.php

◕ helpers.php

◕ include & require_once

The Concept gOld days

● Have to learn

◕ Mindset

◕ Toolset

◗ PHP – Namespaces y autoloader Composer

◗ PHP – Estilo de código, estándar PSR 2

◗ Generación automática de código con IntelliJ y PhpStorm

◕ Domain

◗ Incomprehensible Finder Kata Refactoring ● All is The Concept

The Concept gOld days

ºº

2.MVC frameworks to the rescue

<?phpclass ctrl_frontend extends Controller { function ctrl_frontend() { parent::Controller(); if (!isset($_SESSION)) { session_start(); } } function index() { $this->load->model('sobre_nosotros','',TRUE); $datos['sobreNosotros']=$this-

THE Controller

$datos['sobreNosotros']=$this->sobre_nosotros->getApartados(); $this->load->view('quienes',$datos); break; case 'portfolio': $this->load->model('proyecto','',TRUE); $this->load->model('seguimiento_proyecto','',TRUE); $retorno = $this->proyecto->getProyectosPortfolio(); //primero obtengo los datos de los proyectos if($retorno!=null){ //si hay proyectps $dato["arrayProyectos"] = $retorno; //almaceno los datos obtenidos en un

THE Controller

$this->load->view('proyectoDetalle',$datos); } private function sesionIniciada(){ $this->load->helper('url'); redirect('ctrl_backend_admin/proyectoListar','refresh'); } private function error($msg){ $data["tipoError"]=$msg; $this->load->view('error',$data); }}/* End of file welcome.php *//* Location: ./system/application/controllers/welcome.php */

THE Controller

● Wins ◕ Controller per concept ◕ Isolate views & DB ◕ Active Record discovery

● New ◕ Singletons, singletons everywhere ◕ “Models” & other misconceptions ◕ DB structure defined by ORM

● Still ◕ Highly coupled code ◕ “Software Architecture is for UML people”

The Concept MVC frameworks to the rescue

● Internal doubts

◕ Por qué NO usar getters y setters | Tell don’t ask

◕ Por qué programar sin usar “else” – Cláusulas de guarda

◕ Varios returns en una función: ¿Mal o bien?

◕ Qué son los Code Smells y el Refactoring

◕ Constructores semánticos – Named constructors

The Concept MVC frameworks to the rescue

class CourseController extends FOSRestController{ public function getCourseAction(Request $request) { return $this->getDoctrine() ->getEntityManager() ->createQueryBuilder() ->select('c', 'v') ->from('AppBundle\Model\Course', 'c') ->where('c.level', '>', $request->get('from_level', 0)) ->getQuery() ->execute(); } public function getCourseVideosAction($courseId) { return $this->getDoctrine() ->getEntityManager()

Course controller

bit.ly/codelytv-course-ctrl-fw

class Course extends CourseBaseModel{ public $title; public $level; /** * @return mixed */ public function getTitle() { return $this->title; } /** * @param mixed $title */ public function setTitle($title) { $this->title = $title; }

Course model

bit.ly/codelytv-course-model-anemic

3.The holy grail of testing

● Wins

◕ If you don’t test, you’re going to suffer

◕ SOLID at a micro-design scale ● New

◕ Fragile test due to coupled code bases

◕ Test private methods or not? ● Still

◕ Controller per concept

◕ “Models”, singletons & laravel “facades”

The Concept The holy grail of testing

class CourseControllerTest extends PHPUnit_Framework_TestCase{ public function testGetCoursesFilteredByLevel() { $fromLevel = 0; $request = new Request(['from_level' => $fromLevel]); $container = \Mockery::mock(ContainerInterface::class); $doctrine = \Mockery::mock(Registry::class); $entityManager = \Mockery::mock(EntityManager::class); $queryBuilder = \Mockery::mock(QueryBuilder::class); $query = \Mockery::mock(AbstractQuery::class);

Course controller test

$controller = new CourseController(); $controller->setContainer($container); $controllerResult = $controller->getCourseAction($request); $this->assertEquals( [ [ 'title' => 'Codely mola', 'level' => 2, ], [ 'title' => 'Aprende a decir basicamente como Javi', 'level' => 5, ], ], $controllerResult ); }}

Course controller test

bit.ly/codelytv-course-ctrl-fw-test

● Testing help ◕ Cómo testear código acoplado: Costuras ◕ ¿Puedes ayudarte del #TDD para diseñar software? – Diseños

emergentes

◕ Cómo escuchar a tus test #NaveMisterioCodelyTV

◕ Por qué no usar static ● SOLID ◕ Principio de Responsabilidad Única SRP ◕ Principio de Segregación de Interfaces ISP ◕ Errores comunes al diseñar Interfaces ◕ Principio de Inversión de Dependencias DIP

The Concept The holy grail of testing

4.Serious business

● Wins ◕ Decoupling business logic from framework ◕ Module per concept ◕ Semantics and clean code as something necessary ◕ Ease testing ◕ SOLID at a macro-design scale ◕ DB structure defined by domain

● New ◕ Unlearning process ◕ Deep research aptitude ◕ Theory misinterpretations

The Concept Serious business

The growth stages of a programmer

1st stage 2nd stage 3rd stage

Knowledge Code complexity

Non scientific source :P : https://www.youtube.com/watch?v=2qYll837a_0

final class VideoController extends Controller{ private $bus; public function __construct(CommandBus $bus) { $this->bus = $bus; } public function createAction( string $id, Request $request ) { $command = new CreateVideoCommand( $id, $request->get('title'), $request->get('url'), $request->get('course_id') );

Video controller

public function __construct(CommandBus $bus) { $this->bus = $bus; } public function createAction( string $id, Request $request ) { $command = new CreateVideoCommand( $id, $request->get('title'), $request->get('url'), $request->get('course_id') ); $this->bus->dispatch($command); return new HttpCreatedResponse(); }}

Video controller

bit.ly/codelytv-video-ctrl

final class CreateVideoCommandHandler implements Command{ private $creator; public function __construct(VideoCreator $creator) { $this->creator = $creator; } public function __invoke(CreateVideoCommand $command) { $id = new VideoId($command->id()); $title = new VideoTitle($command->title()); $url = new VideoUrl($command->url()); $courseId = new CourseId($command->courseId()); $this->creator->create( $id, $title, $url, $courseId );

Create video command handler

bit.ly/codelytv-video-handler

final class VideoCreator{ private $repository; private $publisher; public function __construct( VideoRepository $repository, DomainEventPublisher $publisher ) { $this->repository = $repository; $this->publisher = $publisher; } public function create( VideoId $id, VideoTitle $title, VideoUrl $url, CourseId $courseId ) {

Video creator application service

VideoRepository $repository, DomainEventPublisher $publisher ) { $this->repository = $repository; $this->publisher = $publisher; } public function create( VideoId $id, VideoTitle $title, VideoUrl $url, CourseId $courseId ) { $video = Video::create($id, $title, $url, $courseId); $this->repository->save($video); $this->publisher->publish( $video->pullDomainEvents() ); }

Video creator application service

bit.ly/codelytv-video-as

final class Video extends AggregateRoot{ private $id; private $title; private $url; private $courseId; public function __construct( VideoId $id, VideoTitle $title, VideoUrl $url, CourseId $courseId ) { $this->id = $id; $this->title = $title; $this->url = $url;

Video domain model

$this->courseId = $courseId; } public static function create( VideoId $id, VideoTitle $title, VideoUrl $url, CourseId $courseId ) { $video = new self($id, $title, $url, $courseId); $video->record( new VideoCreatedDomainEvent($id) ); return $video; }

Video domain model

bit.ly/codelytv-video-model

final class CreateVideoTest extends VideoModuleUnitTestCase{ /** @var CreateVideoCommandHandler */ private $handler; protected function setUp() { parent::setUp(); $creator = new VideoCreator( $this->repository(), $this->domainEventPublisher() ); $this->handler = new CreateVideoCommandHandler($creator); } /** @test */ public function it_should_create_a_video()

Create video test

public function it_should_create_a_video() { $command = CreateVideoCommandStub::random(); $video = VideoStub::fromRawValues( $command->id(), $command->title(), $command->url(), $command->courseId() ); $event = VideoCreatedDomainEventStub::fromRawValues( $command->id(), $command->title(), $command->url(), $command->courseId() ); $this->shouldSaveVideo($video); $this->shouldPublishDomainEvents([$event]); $this->dispatch($command, $this->handler); }

Create video test

bit.ly/codelytv-video-test

● Tips / knowledge we’d like to have had

◕ Caso real de replanteamiento de diseño de Software

◕ Explicar Refactorings de forma didáctica – QWAN Cards

◕ Introducción Arquitectura Hexagonal – DDD

The Concept Serious business

5.Bigger & faster

● Wins:

◕ (SOLID + Software Architecture theory + Testing) accomplished

◕ Bounded context (even microservices) per concept

◕ More teams ● New:

◕ Accidental complexity (infrastructure, coordination…)

The Concept Bigger & faster

6.Recap

● There’s no silver bullet approach. All depends on the context, and the context will evolve.

● Conclusion: The Concept must be easy to promote with context evolutions

◕ From framework to modules:

◗ Decouple from outside infrastructure in order to isolate the domain

◗ Isolate use cases and work on cohesion

◕ From modules to Bounded Context:

◗ Decouple using buses to interact between them

◕ From whatever to Microservices:

◗ You don’t have to promote anything. This is not a change in terms source code but in terms of infrastructure

The Concept Recap

Tabla molonaFramework

coupled code Modules Bounded Contexts Microservices

Learning curve Low Medium High High++

Teams autonomy Low Medium+ High High++

Infrastructure Shared (& coupled) Shared Individual Individual &

distributed

Code maintainability/

extensibilityLow— High High+ High++

Infrastructure complexity Low Medium Medium High++++

Communication between them Coupled Buses Buses Distributed buses

Deploy Shared Shared Shared Isolated

We’re not promoting microservices per se. Due to infrastructure and accidental complexity It could be the worst option actually.

Takeaways

Takeaways

● Unit Testing sucks (and it’s our fault) - José Armesto ● Vídeos sobre SOLID - CodelyTV ● Hexagonal Architecture - Chris Fidao ● Introducción Arquitectura Hexagonal – DDD - CodelyTV ● Domain-Driven Design in PHP - Carlos Buenosvinos, Christian Soronellas

and Keyvan Akbary ● A wave of command buses - Matthias Noback ● How to Avoid Building a Distributed Monolith - Felipe Dornelas ● PHP Barcelona Monthly Talk: DDD Applied & Symfony MPWAR Edition -

Sergi González & Eloi Poch ● Implementing Domain-Driven Design - Vaughn Vernon ● This talk repositories (to be published on github.com/CodelyTV)

Questions?

Thanks!Contact

@JavierCane

@CodelyTV@Rafaoe