Aesthetics and the Beauty of an Architecture

Preview:

DESCRIPTION

CQRS & Event Sourcing are patterns gaining traction and popularity. In this presentation given at Øredev 2013 it talks about real-world experiences using these patterns, the good, the bad and the ugly.

Citation preview

Aesthetics & the Beauty of an Architecture

Tom Scott @tomwscott

Adventures in CQRS & Event Sourcing

What’s in it for you?

• Understanding of CQRS & Event Sourcing in the wild

• The mistakes we made…

• … the lessons we learnt …

• … and why we’re still happy!

rob.knight

art 1 |ɑːt| noun 1 [ mass noun ] the expression or application of human creative skill and imagination, typically in a visual form such as painting or sculpture, producing works to be appreciated primarily for their beauty or emotional power

art 1 |ɑːt| noun 1 [ mass noun ] the expression or application of human creative skill and imagination, typically in a visual form such as painting or sculpture, producing works to be appreciated primarily for their beauty or emotional power

Aesthetics

Scott’s Purely Arbitrary Criteria, Etceteras

For Evaluating Beautiful Architectures

Etceteras

Aesthetics

#SPACE_FEBA

Fully Operational

Simplicityecherries

Commitmentjustageek

Deferring Commitmentjustageek

MetaphorPetar Pavlov - http://bit.ly/9ySEUt

Discipline & Consistency

Serendipity

kathryn_rotondo

• Fully Operational

• Simplicity

• Deferred Commitment

• Metaphor

• Discipline

• Serendipity

#SPACE_FEBA

Price Comparison

!"

####

$

$

% $

$

&

££

The evolution of a system

'

%

|

Presentation

Application

Database

)*+

The Solution

archer10

Architectural Goals

• Structured

• Horizontal Scalability

• Availability & Reliability

• Visibility / Monitorability

• Flexibility & Replaceability

archer10

The Mandate!

• Service Oriented Architecture

• Domain Driven Design

• Micro-Services

• Continuous Delivery

• Oh and one more thing!

archer10

Domain Driven Design

• Entity

• Value Object

• Aggregate

• Service

• Repository

• Factory

• Bounded Context

archer10

Domain Driven Design

archer10

• Entity

• Value Object

• Aggregate

• Service

• Repository

• Factory

• Bounded Context

%

'

Service Oriented Architecture

% % ''

% '

Understand your Domain

!

####Home

JourneyPanel Quote

Engine

% % ''

"

Risk Enquiry Provider Quote

The End??

Just one more thing…http://m.cdn.blog.hu/ke/kedvessigmund/image/columbo.jpg

CQRS & Event Sourcing

• CQRS or “Why do we use the same schema for reads and writes?”

• Event Sourcing or “Why do we allow ORMs to dictate our object model?”

archer10

CQRS

Command Query Responsibility Segregation

,

, ,

, ,write

}read

}

UPDATE  Address    SET    number  =  10,            street  =  ‘Downing  Street’,            city  =  ‘London’,            postcode  =  ‘SW1A  2AA’  WHERE  _id  =  ‘590b9902’

{          “_id”  :  “590b9902”,          “event”  :  “PolicySpecified”,          “data”  :  {             “type”  :  “ContentsInsurance”,       “excess”  :  750      }  }

{          “_id”  :  “590b9902”,          “event”  :  “AddressModified”,          “data”  :  {             “number”  :  10,       “street”  :  “Downing  Street”,              “city”  :  “London”,       “postcode”  :  “SW1A  2AA”      }  }

Use SQL?

-

,./

%

/

/ / / / /

     public  class  Customer  :  AggregateRoot        {                  private  readonly  Guid  id;  !                private  Address  currentAddress;                                  //  Business  Logic                  public  void  ChangeAddress(Address  newAddress)                  {                if  (newAddress.IsValid())             {                                 Raise(new  AddressModified(id,  newAddress));                                 }                  }                !                //  State  Transition                  public  void  Apply(AddressModified  @event)                    {                          currentAddress  =  @event.Address;                  }  !!       ......  !!                //  Business  Logic                  public  void  SpecifyCommunicationPreferences(CommunicationPrefs  preferences)                  {                          Raise(new  CommunicationPreferencesSpecified(id,  preferences));                                  

Event Sourcing (C#)

Eventual Consistency

% '

!

-

,.

/ / / / /

POST /risk/new GET /risk/590b9902:v1

/

HTTP/1.1 302 !Location: /risk/590b9902:v1

0

What we ended up with:% '-

% '-

% '-

% '-

% '-

# # # # # # # # # #

)* +

1

2 % '-

2% '-

2

The Conclusion

tim_norris

Fully Operational

Simple

Commitment

Metaphor

Discipline

Serendipity

3 +?

3?3

The Power!

     public  class  Customer  :  AggregateRoot        {                  private  readonly  Guid  id;  !                private  Address  currentAddress;  !                public  void  ChangeAddress(Address  newAddress)                  {                                              Raise(new  AddressModified(id,  newAddress));                                        }  !                public  void  Apply(AddressModified  @event)                  {                          currentAddress  =  @event.Address;                  }          }

The Power!      public  class  Customer  :  AggregateRoot        {                  private  readonly  Guid  id;  !                private  Address  currentAddress;  !                public  void  ChangeAddress(Address  newAddress)                  {                          if  (currentAddress.IsSignificantlyDifferentFrom(newAddress))                          {                                  Raise(new  CustomerMoved(id,  newAddress));                          }                          else                          {                                  Raise(new  AddressModified(id,  newAddress));                          }                  }  !                public  void  Apply(CustomerMoved  @event)                  {                          currentAddress  =  @event.Address;                  }  !                public  void  Apply(AddressModified  @event)                  {                          currentAddress  =  @event.Address;                  }          }

The Flexibility!

var  connection  =  rabbit.createConnection({  url:  ‘amqp://localhost:5672'  })  !connection.on('ready',  function  ()  {          console.info('Connected');          exchange  =  connection.exchange('SOURCE:Exchange',  {  'type':  'topic',  durable:  true  },  function  ()  {                  var  queue  =  connection.queue('PROJECTION:Map',  {  durable:  false,  exclusive:  true  },                  function  ()  {                          console.info("Joined  Queue");                          queue.subscribe(function  (message,  headers,  deliveryInfo)  {                                  var  policyDetails  =  JSON.parse(message.data.toString());                                  io.sockets.emit('postcode',  policyDetails.Address.Postcode);                          });                          queue.bind(exchange.name,  'AddressDetailsSpecified');                  });                  queue.on('queueBindOk',  function  ()  {  console.info('Bound  queue  to  exchange');  });          });  !});

Is it a silver bullet?

rob.knight

Lessons Learnt

• Prefer simpler communication protocols

• Messaging == Push == Transient,

• HTTP == Pull == Permanent

• Difficult to evolve Domain Events

• Events as the system contract

Thank You!!

Tom Scott @tomwscott

Recommended