68
From Rails legacy to DDD @andrzejkrzywda Arkency

From Rails legacy to DDD - Pivorak, Lviv

Embed Size (px)

Citation preview

From Rails legacy

to DDD

@andrzejkrzywda Arkency

Agenda

• What is legacy

• Why and when Rails becomes legacy

• What is DDD

• Why it’s worth learning

• How to gradually go DDD - lessons learnt

Andrzej Krzywda• 11 years with Rails

• running Arkency (Ruby agency)

• writing Ruby-related books

• RailsRefactoring.com

• blogging

• teaching Rails at University of Wroclaw (for the last 5 years)

• organising wroc_love.rb

• DRUG meetups in Wrocław

Andrzej Krzywda

• reviewed hundreds of Rails apps

• helped several Rails teams

• dealing with bigger Rails apps

What is legacy code?

Legacy

• Frameworks

• monolithic

• no architecture

• no tests

• “code written yesterday”

• “code written by someone else”

• “not my code”

• “not in my favourite architecture”

How do Rails apps become legacy?

Rails is optimised for the first weeks of development

Bringing us joy and speed

Optimised for adding new forms/tables/

columns

Not optimised for complex business logic

Refunding a ticket

What are the symptoms?

• slow tests

• the test setup is long and complicated

• critical bugs more often

• slower development progress

• conflicts in the team, related to the code

• complicated codebase

• infinite API

DDD Domain-Driven Design

DDD aims to help with complex business logic

Most popular in .NET and Java, but also strong in

the PHP community

Why is DDD not popular in the Rails community?

Mostly due to our Java-hate DNA

Why it’s worth learning DDD?

• New techniques • new tools • Solutions to complicated business

logic • solutions in non-Ruby worlds • shared language with other

programmers • microservices!

How to start?

Service objects are the gateway drug

Strategic vs Tactical DDD

Tactical DDD• entity

• value objects

• aggregate

• domain event

• services

• repositories

• factory

DDD-lite• app service

• calls 1 or more domain services

• domain service

• takes repo as input

• load aggregate from the repo

• do sth cool

• may use some value objects

• may trigger some domain events

• save aggregate (repo)

• URL

• Rails action

• App service

• Domain service

• Repo

• ActiveRecord

• Database

One app service can call multiple domain services

UpdateCustomer ==

MoveToNewAddress ChangeEmail

IntroduceNewContactPerson

In one of our projects one request was about 15 domain services

“Update” is always hiding a lot

application vs

domain

Strategic DDD

• bounded contexts

• context map

Warning: next slide is almost like UML

http://martinfowler.com/bliki/BoundedContext.html

Software House management tool

optionally as microservices partially available

different persistencedata duplication

Context MapHR Project Management Finances

Invoicing

CRUD

DDD-lite

external SaaS

Communication

developer project client

DDD-lite

bounded contexts as namespaces in Ruby

How to get there from legacy?

BTW, There’s no such thing as the ultimate DDD codebase

Draw the Context Mapaka what are the boxes in your application

aka you have more appsThey are potential microservices

Decide which contexts are CRUD and which ones

need more logic (DDD-lite)the ones with CRUD ideally need to publish events anyway

Bounded contexts

• Inventory

• Invoicing

• Ordering

• Finances

• Forum

Ongoing processNo time for 2-months rewrites

Peopleware the human factor

http://andrzejonsoftware.blogspot.com/2014/01/refactoring-human-factor.html

Escape from the CRUD verbsTalk more to the business people

decrease Convention over Configuration

Test coverage

#noregressions

when you’re a client you don’t like them too

Line coverage* is

a joke*rcov, simplecov

Mutation testing is the real test coverage!

http://blog.arkency.com/2015/04/why-i-want-to-introduce-mutation-testing-to-the-rails-event-store-gem/

http://blog.arkency.com/2015/06/how-good-are-your-ruby-tests-testing-your-tests-with-mutant/

You want to try mutant

(today)

mutant ==

testing your tests ==

refactoring with confidence

Test units, not classes!http://andrzejonsoftware.blogspot.com/2015/02/tdding-unit-not-class.html

http://andrzejonsoftware.blogspot.com/2014/04/tdd-and-rails-what-makes-good-unit.html

http://blog.arkency.com/2014/09/unit-tests-vs-class-tests/

Escape from the framework ASAP

http://blog.arkency.com/2015/03/extract-a-service-object-in-any-framework/

Call application services from the framework

let Rails deal only with HTTP

Don’t just pass the params/hash everywherehttp://andrzejonsoftware.blogspot.com/2011/12/args-opts-params.html

Wrap your legacy contexts with the

application services layer

Use events to communicate between

bounded contextsrails_event_store

https://github.com/arkency/rails_event_store

Sync may be safer than async

Separate reads/writes at the services layer

CQRS

Eliminate querying from BC to another

Push the data!

Keep the Bounded Contexts in-sync by publishing all the

important events

Easier testing when no dependency on other

system

Read modelsDenormalized data

When in doubt, think in aggregates

Roles in DDD

http://andrzejonsoftware.blogspot.com/2015/09/dci-ddd-and-concept-of-roles.html

Event sourcingbuild your aggregates from events

audit log for free

Distributed transactions are tricky

Easier setup of the project when it’s a smaller

pieceUseful when you’re maintaining many projects and need to bugfix them from time to time

Legacy -> DDD books

• red book, Vaughn Vernon

• Implementing DDD

• blue book, Eric Evans

• Refactoring, Fowler

• Legacy code, Feathers

THANKS!