Use Case Driven Development in Symfony

Post on 11-Apr-2017

562 views 1 download

Transcript of Use Case Driven Development in Symfony

USE CASE DRIVEN DEVELOPMENT IN SYMFONY

Bartosz Zasada zasada.bartosz@gmail.com

ABOUT ME

➤ From Toruń, Poland

➤ Software developer since 2010

➤ In Berlin since July 2015

➤ Bass player

WHAT ARE YOU WORKING ON?

HOW CAN I USE YOUR WEBSITE?

HOW CAN I USE YOUR WEBSITE?

➤ You can buy a lot of different stuff and have it delivered the very next day.

➤ You can cheaply book a room for your vacation in a nice hotel.

➤ You can order a meal, making your choice basing on opinions shared by other users.

➤ You can watch videos of kittens and participate in endless flame wars in the comments section.

USE CASES

ACTORS

➤ An actor is anyone (or anything) that interacts with the application

➤ Different actors have their own specific needs

➤ One person can have a role of many actors

USE CASES

➤ A use case is a specific way of using the system by using some part of the functionality

➤ When all actors are known, identifying their needs will define the complete functionality of the application

EXAMPLES OF USE CASES

➤ View products in category

➤ View product page

➤ Add product to shopping cart

➤ Place order

➤ Mark payment as paid

➤ Dispatch shipment

➤ Add product to stock

➤ Set discount for product

Customer

Customer Service

Inventory Manager

COURSES OF EXECUTION

➤ The primary course of the use case is a series of events that lead to the one successful outcome

➤ The use case can also follow one of the alternative courses, which usually means that something went wrong

➤ Product does not exist

➤ Product is out of stock

➤ The quantity is not a positive integer

➤ The maximum quantity was exceeded

➤ A system failure has occurred

IMPLEMENTING USE CASES

ONE USE CASE, ONE CLASS

➤ Isolate the application behavior in a class that represents a Use Case

➤ Identify the incoming data and create a Request object

➤ Return the result as a single Response object

➤ Or throw an Exception if something goes wrong

IMPLEMENTATION EXAMPLE

IMPLEMENTATION EXAMPLE

BUT THAT'S MY CONTROLLER ACTIONS!

➤ Okay, but...

➤ The controllers depend on classes that belong to HttpFoundation

➤ Often you have to inject the entire HTTP request

➤ Always you have to return an HTTP response

➤ The use cases are mixed with details that have nothing to do with business logic

SO WHAT?

➤ HTTP requests and responses are specific to web applications

➤ They can come in different forms regardless of the logic

➤ GET - query string or route attributes

➤ POST - form_params or JSON (or XML) in the body

➤ Response - HTML, JSON, XML

➤ Exporting data - XML, CSV, PDF...

➤ Business logic should be clearly separated from these details

USE CASES ARE SOLID

➤ Single Responsibility Principle is clearly visible: each Use Case defines a single possible interaction of a user with the application

➤ By having the Use Cases follow the same pattern, the system becomes open for extension and closed for modification, as the new functionality is added by creating new classes rather than modifying the existing ones - thus following the Open-Closed Principle

➤ Use Cases favor Interface Segregation Principle: every interface upon which a Use Case depends defines needs specific to this Use Case

INTERFACE SEGREGATION PRINCIPLE

Display Products in Category Category Repository

Display Featured Categories

Featured Category Repository

Display Category Tree

Category Tree Repository

Doctrine Category Repository

USE CASES ARE SOLID

➤ Use Cases follow the Dependency Inversion Principle

➤ Instead of having business logic depend on HTTP requests and responses, the HTTP layer becomes dependent on Use Case Requests and Use Case Responses

DEPENDENCY INVERSION PRINCIPLE

Use Case HTTP Request

HTTP RequestUse Case Use Case Request

ALL THAT BOILERPLATE

INTRODUCING USE CASE BUNDLE

INSTALLATION

➤ composer require bamiz/use-case-bundle ➤ AppKernel.php: new Bamiz\UseCaseBundle\BamizUseCaseBundle()

USAGE

services.yml

Use Case

Controller

HANDLING INPUT

➤ Input is whatever the application receives from its user

➤ The Use Case is resolved based on Input

➤ The Use Case Request is created for the Use Case

➤ An Input Processor parses the Input and initializes the fields of the Use Case Request

Use CaseUse Case RequestInput Processor

CREATING OUTPUT

➤ Output is whatever the user sees as the result of the application's operation

➤ The Use Case Response is returned by the Use Case

➤ An Exception is thrown by the Use Case

➤ A Response Processor creates the Output using the data contained in the Response or Exception

Use Case Use Case Response Response Processor

CONFIGURING PROCESSORS FOR USE CASES

DEPENDENCIES

Use Case Request

Input

Use Case

Output Input Processor

Response Processor

Use Case Response

BUNDLED PROCESSORS

➤ Input Processors

➤ HTTP - populates the fields with data from HTTP Request

➤ Form - uses Symfony Forms to initialize the Request

➤ JSON - Decodes request body as JSON

➤ Response Processors

➤ JSON - returns the Response as JsonResponse

➤ Twig - renders Twig templates using Response as params

YOUR OWN PROCESSORS

➤ Input Processor

➤ Implement InputProcessorInterface

➤ Create a service and tag it as use_case_input_processor

➤ Response Processor

➤ Implement ResponseProcessorInterface

➤ Create a service and tag it as use_case_response_processor

SO MUCH ROOM TO GROW

IDEAS FOR FEATURES

➤ Chaining Input and Response Processors

➤ In progress Done

➤ An Input Processor that ensures the correct types of the fields

➤ Types read from @var/@type in PHPDoc

➤ "1 234,56" → (float)1234.56

➤ "true"/"1"/"on" → (bool)true; ➤ "false"/"0"/"" → (bool)false

➤ More configuration options

➤ Defaults per Processor (globally or in context)

➤ Defining contexts per Use Cases using YAML

IDEAS FOR FEATURES

➤ Actors

➤ Integration with Symfony Security component

➤ Use Cases restricted to certain Actors

➤ Actors executing their Use Cases reflected in code syntax ➤ $this->registeredUser->addItemToWishlist() ➤ $this->customer->viewProductPage()

IDEAS FOR FEATURES

➤ Code that writes itself

➤ Symfony Command that generates Use Cases, Requests and Responses

➤ Use Cases generated using Behat scenarios

➤ Scenario: Viewing product page

➤ As a customer

➤ I want to view the product page

➤ So that ...

YOU'RE WELCOME TO CONTRIBUTE

➤ https://github.com/bartosz-zasada/use-case-bundle

➤ If you fork, you are awesome already

➤ Make a pull request and you're super awesome

➤ Let's make our software great together

➤ Love it? Hate it? Got an idea? Drop me a message: zasada.bartosz@gmail.com

INSPIRATION

➤ https://www.youtube.com/watch?v=WpkDN78P884

➤ Object Oriented Software Engineering: A Use Case Driven Approach. Ivar Jacobson et al.

➤ Agile Software Development: Principles, Patterns, and Practices. Robert C. Martin

➤ Videos from http://cleancoders.com

QUESTIONS?

THANK YOU 🙂