groovy architectural flexibility

Post on 24-May-2015

523 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Understand the forces on your codebase in different areas to discover the best way in each context to develop code. Using the different features of groovy to react to those pressures and preserve your room for manouvre.

TRANSCRIPT

Architectural Flexibility

using Groovy

David Dawson

CEO, Principal Consultant

david.dawson@simplicityitself.com

@davidthecoder

What kind

of

Code is Best?

Object Oriented

or

Functional?

Strongly Typed

or

Weakly Typed?

To Meta

or

Not to Meta?

Data

or

Type

Why?

●Non functional requirements

[tx/ sec, latency, deployment etc]

●Non functional requirements

[tx/ sec, latency, deployment etc]

●Developer Comprehension

●Non functional requirements

[tx/ sec, latency, deployment etc]

●Developer Comprehension

●Coding Style

●Non functional requirements

[tx/ sec, latency, deployment etc]

●Developer Comprehension

●Coding Style

●Data Model(s)

●Non functional requirements

[tx/ sec, latency, deployment etc]

●Developer Comprehension

●Coding Style

●Data Model(s)

●Others … [bias...?]

Forces on Code

What kind

of

Code is Best?

WrongQuestion

Core Domain

Application PoliciesBusiness Rules

Core Domain

Application PoliciesBusiness Rules

Core Domain

Application PoliciesBusiness Rules

REST

Core Domain

Application PoliciesBusiness Rules

REST

Events

Core Domain

Application PoliciesBusiness Rules

RESTProvided API

Events

Core Domain

Application PoliciesBusiness Rules

RESTProvided API

UserDSL

Events

Context

Core Domain

Application PoliciesBusiness Rules

RESTProvided API

UserDSL

Events

Core Domain

Application PoliciesBusiness Rules

Core Domain

Application PoliciesBusiness Rules

Core Domain

Application PoliciesBusiness Rules

Core Domain

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

● Understand Identity

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

● Understand Identity

● Use Ubiquitous Language

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

● Understand Identity

● Use Ubiquitous Language

● Relatively high code churn

OrderMenu

Recipe

OrderMenu

Recipe

orderId

recipeId

menuId

class OrderService {

}

def process( def order ) { if (valid(order)) { dispatch(order) persist(order) return OrderResult.SENT } OrderResult.INVALID //or similar}

class OrderService {

}

process( Order order ) { if (valid(order)) { dispatch(order) persist(order) return OrderResult.SENT } OrderResult.INVALID //or similar}

OrderResult

class OrderService {

}

process( Order order ) { if (valid(order)) { dispatch(order) persist(order) return OrderResult.SENT } OrderResult.INVALID //or similar}

OrderResultvalidateAndDispatch

Core Domain

Application PoliciesBusiness Rules

REST

Events

Provided API

UserDSL

Events

Events

EventsEvent Processor

EventsEvent Processor

Subscription

Subscription

Subscription

EventsEvent Processor

Subscription

Subscription

Subscription

Event

EventsEvent Processor

Subscription

Subscription

Subscription

Events

Forces

Event Processor

EventsEvent Processor

Forces● Performance

EventsEvent Processor

Forces● Performance

● Technically focused, technical language

EventsEvent Processor

Forces● Performance

● Technically focused, technical language

● No interest in type or identity

EventsEvent Processor

Forces● Performance

● Technically focused, technical language

● No interest in type or identity

● Interest in functionality

EventsEvent Processor

Forces● Performance

● Technically focused, technical language

● No interest in type or identity

● Interest in functionality

● Data/ algorithm oriented

class EventProcessor {

List<Subscription> subscriptions

}

void process(Message message) { subscriptions.findAll { it.canHandle(message) }.each { it.dispatch(message) }}

class EventProcessor {

List<Subscription> subscriptions

}

void process(Message message) { subscriptions.findAll { it.canHandle(message) }.each { it.dispatch(message) }}

class EventProcessor {

List<Subscription> subscriptions

}

void process(Message message) { subscriptions.findAll { it.canHandle(message) }.each { it.dispatch(message) }}

200k messages : 450ms

class EventProcessor {

List<Subscription> subscriptions

}

void process(Message message) { for(Subscription sub in subscriptions) { if(it.canHandle(message)) {

it.dispatch(message) } }}

80ms200k messages : 450ms

class EventProcessor {

List<Subscription> subscriptions

}

@CompileStaticvoid process(Message message) { for(Subscription sub in subscriptions) { if(it.canHandle(message)) {

it.dispatch(message) } }}

30ms200k messages : 450ms 80ms

Core Domain

Application PoliciesBusiness Rules

REST

Events

Provided API

UserDSL

Core Domain

Application PoliciesBusiness Rules

REST

Events

Provided API

UserDSL

Core Domain

Application PoliciesBusiness Rules

REST

Core Domain

Application PoliciesBusiness Rules

REST

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Forces

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Forces● Interested only in integration

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Forces● Interested only in integration

● Designed to remove type

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Forces● Interested only in integration

● Designed to remove type

● Affinity with Data & Values

Core Domain

Application PoliciesBusiness Rules

RESTDomain Transformer

Forces● Interested only in integration

● Designed to remove type

● Affinity with Data & Values

● Data Transformation

class OrderTransformer {

}

def send(Message message) { RestMessage msg = New RestMessage()

msg.txt = message.text target.doProcessing(msg)}

class OrderTransformer {

}

def send(Message message) { RestMessage msg = New RestMessage()

msg.txt = message.text target.doProcessing(msg)}

class OrderTransformer {

}

def send(Message message) { RestMessage msg = New RestMessage()

msg.txt = message.text target.doProcessing(msg)}

msg.txt = message.text target.doProcessing(msg)

def msg=[txt:message.text] target.doProcessing(msg)

def transformer = { target, message ->

def msg=[text:message.text] target.doProcessing(msg) }

def transformer = { message, target ->

def msg=[txt:message.text] target.doProcessing(msg) }

transformer = transformer.curry(aTarget)transformer(text:”Hello GGX!”)

Core Domain

Application PoliciesBusiness Rules

REST

Events

Provided API

UserDSL

UserDSL

UserDSL

Domain SpecificLanguage

UserDSL

Domain SpecificLanguage

Forces

UserDSL

Domain SpecificLanguage

Forces● User Comprehension

UserDSL

Domain SpecificLanguage

Forces● User Comprehension

● Expressiveness

UserDSL

Domain SpecificLanguage

Forces● User Comprehension

● Expressiveness

● Ease of Use versus Intuitive

def orders = Order.findAllByUserName(“someone”)

def orders = Order.findAllByUserNameAndOrderTax\BetweenOrOrderValueLessThanAndAddress1Like( “someone”, 5, 6, 15.20, “%Some Street%”)

def orders = Order.findAllByUserNameAndOrderTax\BetweenOrOrderValueLessThanAndAddress1Like( “someone”, 5, 6, 15.20, “%Some Street%”)

def orders = Order.findAll { username == “someone” orderValue in [5 .. 6] address1 =~ “%Some Street%”}

def orders = Order.findAllByUserNameAndOrderTax\BetweenOrOrderValueLessThanAndAddress1Like( “someone”, 5, 6, 15.20, “%Some Street%”)

def orders = Order.findAll { username == “someone” orderValue in [5 .. 6] address1 =~ “%Some Street%”}

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

● Understand Identity

● Use Ubiquitous Language

● Relatively high code churn

Core Domain

Application PoliciesBusiness Rules

Core Domain

Forces● Express Type

● Understand Identity

● Use Ubiquitous Language

● Relatively high code churn

List<Order> findAuthorisedRecords(User user) {

List<Order> orders = Orders.list()

List<Order> selectedOrders = new ArrayList<>();

for(Order order: orders) { if(order.user == user) { SelectedOrders << order }}

return Collections.sort(selectedOrders)

}

List<Order> findAuthorisedRecords(User user) {

List<Order> orders = Orders.list()

List<Order> selectedOrders = new ArrayList<>();

for(Order order: orders) { if(order.user == user) { SelectedOrders << order }}

return Collections.sort(selectedOrders)

}

List<Order> findAuthorisedRecords(User user) {

List<Order> orders = Orders.list()

List<Order> selectedOrders = new ArrayList<>();

for(Order order: orders) { if(order.user == user) { selectedOrders << order }}

return Collections.sort(selectedOrders)

}

List<Order> findAuthorisedRecords(User user) {

def orders = Orders.list()

def selectedOrders = []

for(def order: orders) { if(order.user == user) { selectedOrders << order }}

return Collections.sort(selectedOrders)

}

List<Order> findAuthorisedRecords(User user) {

def orders = Orders.list()

def selectedOrders = orders.findAll { order.user == user}

return Collections.sort(selectedOrders)

}

List<Order> findAuthorisedRecords(User user) {

def orders = Orders.list()

return orders.findAll { order.user == user}.sort { order.id}

}

List<OrderDetails> findAuthorisedRecords(User user) {

def orders = Orders.list()

return orders.findAll { it.user == user}.sort { it.id}.collect { it as OrderDetails}

}

Understand Context

Understand Context

Identify Forces

Understand Context

Identify Forces

Drive Code

Understand Context

Identify Forces

Drive Code

Reject Dogma

Questions

@davidthecoder

Thank you!

@davidthecoder

top related