Busy Java Developer's Workshop using Apche Isis Ted Neward Neward - - PowerPoint PPT Presentation

busy java developer s workshop using apche isis
SMART_READER_LITE
LIVE PREVIEW

Busy Java Developer's Workshop using Apche Isis Ted Neward Neward - - PowerPoint PPT Presentation

Busy Java Developer's Workshop using Apche Isis Ted Neward Neward & Associates http://www.tedneward.com | ted@tedneward.com Objectives Why are we here? Explore concepts around "domain objects" specifically, the idea of


slide-1
SLIDE 1

Busy Java Developer's Workshop using Apche Isis

Ted Neward Neward & Associates http://www.tedneward.com | ted@tedneward.com

slide-2
SLIDE 2

Objectives

Why are we here?

– Explore concepts around "domain objects"

specifically, the idea of using them to build an application

– Understand the history of Smalltalk and MVC – Play around with NakedObjects

  • Apache Isis (Java)
  • RestfulObjects (HTTP-API)
slide-3
SLIDE 3

Credentials

Who is this guy?

– Principal -- Neward & Associates – Director -- Developer Relations, Smartsheet.com – Microsoft MVP (F#, C#, Architect); Java Expert (JSRs 175, 277) – Author

Professional F# 2.0 (w/Erickson, et al; Wrox, 2010) Effective Enterprise Java (Addison-Wesley, 2004) SSCLI Essentials (w/Stutz, et al; OReilly, 2003) Server-Based Java Programming (Manning, 2000)

– Blog: http://blogs.tedneward.com – Writing: http://www.newardassociates.com/#/writing – Twitter: @tedneward – For more, see http://www.newardassociates.com/#/about

slide-4
SLIDE 4

Format

How we gonna do this?

slide-5
SLIDE 5

Format

Lecture/lab format

– I will lecture for a bit – You will code/debug/explore for a bit

I will try to wander the room and help where I can

– Lather, rinse, repeat – Turn in your evals and you are free!

slide-6
SLIDE 6

Format

"The Rules"

– Pairing and interaction

absolutely encouraged

– Googling/Binging/looking stuff up online

absolutely encouraged

– Leaving the room during a "lab"

absolutely encouraged (if necessary)

– Jumping ahead

encouraged, but I can only help for "this" step

slide-7
SLIDE 7

Format

"Requests"

– set the phone/volume/etc to vibrate

basically, don't disturb the neighbors

– ask questions!

if you're thinking it, so are other people

– ... but let's keep the focus to the here and now

there's a lot to cover, so I need to keep us focused

slide-8
SLIDE 8

Format

Ready?

– Any questions? – If not, here we go.... – Last chance... abandon hope, all ye who remain...

slide-9
SLIDE 9

History

Where it all began

slide-10
SLIDE 10

Smalltalk: Overview

The original O-O language

slide-11
SLIDE 11

Overview

Smalltalk is...

– object-oriented – dynamically-typed – message-passing – reflective

... programming language ... and environment

slide-12
SLIDE 12

Overview

Current Smalltalk implementations

– Amber (runs in Javascript browsers!)

http://www.amber-lang.net/

– Squeak

https://en.wikipedia.org/wiki/Squeak

– GNU Smalltalk

https://en.wikipedia.org/wiki/GNU_Smalltalk

– Concomm Smalltalk (ObjectStudio, VisualWorks)

http://www.cincomsmalltalk.com/main/

– Pharo

http://pharo.org/

slide-13
SLIDE 13

Smalltalk

A History

slide-14
SLIDE 14

History

Smalltalk's history is long and distinguished

– began development in 1969 – developed at Xerox PARC – invented by Alan Kay (with help from Dan Ingalls) – influenced by Lisp, Simula, Logo, Sketchpad – first release -- Smalltalk-71 – first public release -- Smalltalk-80

slide-15
SLIDE 15

History

Smalltalk influenced...

– AppleScript – Common Lisp Object System – Dart – Dylan – Erlang – Etoys – Falcon

slide-16
SLIDE 16

History

Smalltalk influenced...

– Go – Groovy – Io – Ioke – Java – Lasso – Lisaac

slide-17
SLIDE 17

History

Smalltalk influenced...

– Logtalk – NewtonScript – Object REXX – Objective-C – PHP 5 – Perl 6

slide-18
SLIDE 18

History

Smalltalk influenced...

– Python – Ruby – Scala – Scratch – Self

slide-19
SLIDE 19

History

Began on a bet

– can a programming language based on the idea of message passing inspired by Simula be implemented in 'a page of code'? – incidentally, Kay answered that in "a few mornings"

slide-20
SLIDE 20

History

Objects introduced in Smalltalk-80

– Smalltalk object can do three things:

  • hold state (references to other objects)
  • receive a message from itself or another object
  • in the course of processing a message, send a message to

itself or another object

– no difference between values which are objects and primitive types – "in Smalltalk everything is an object" – classes are also instances of objects

slide-21
SLIDE 21

History

Smalltalk incorporated IDE and runtime into one tool

– this is the "Smalltalk browser" – objects were visual objects – manipulate the objects to manipulate the environment – image files were of the entire runtime

slide-22
SLIDE 22

Model/View/Controller

Separating display from logic

slide-23
SLIDE 23

Model/View/Controller

MVC is a design pattern that appears frequently in GUI systems

– Model represents the state – Controller represents the logic – View represents the display/UI

slide-24
SLIDE 24

Model/View/Controller

Origins lie in Smalltalk

– Models were objects – Controllers were objects – Views were objects – Today, this is an idiom known as "Naked Objects"

slide-25
SLIDE 25

Model/View/Controller

MVC showed up in a number of GUI systems

– Windows UI frameworks called it "Document/View" – Java Swing built around MVC quite deeply

  • tables, lists, all used models extensively
  • even the actual UI code was split along view/controller lines;

AbstractButton defined basic button behavior, and deferred to another class to do the actual pixel-drawing work

– iOS uses it (ViewControllers are controllers)

slide-26
SLIDE 26

Model/View/Controller

In the original MVC...

– Models were often connected to more than one View – Controllers coordinated view updates as model changed – Models, Views and Controllers relatively loosely coupled – Web adaptation of MVC changed this to a 1:1 View/Controller

Web views and controllers never reused

slide-27
SLIDE 27

Model/View/Controller

Parting thoughts

– Models are not necessarily Domain Objects

community is split over this one

– Views should not contain "logic"

  • except for logic that is UI-focused
  • community is split over this one too
slide-28
SLIDE 28

Model/View/Controller

MVC has spawned a lot of similar ideas/patterns

– Hierarchical model-view-controller – Model-view-adapter – Model-view-presenter – Model View ViewModel – Observer – Presentation-abstraction-control – Three- or n-tier architecture

slide-29
SLIDE 29

Model/View/Controller

Resources

– For more details, see

http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80 %93controller

– Observer pattern comes from "Design Patterns" (GOF book)

Gamma, Helm, Johnson, Vlissides

– Presentation-abstraction-control comes from "POSA 1"

Buschmann, Meuneir, Rohnert, Sommerlad, Stal

slide-30
SLIDE 30

Naked Objects

Wait.... what?

slide-31
SLIDE 31

Naked Objects: Overview

In the old days...

– objects were intended to be directly user-manipulable things

  • data directly modified/changed
  • methods directly invoked
  • connections directly displayed/modified

– ... but we have since lost that simple idea

slide-32
SLIDE 32

Naked Objects: Overview

What's wrong with the way we do applications today?

– too much complexity in the UI code – too many opportunities to get the business rules wrong – too much time spent building the system – too much effort required to understand/maintain it

slide-33
SLIDE 33

Naked Objects: Overview

New idea: Let the UI center around the objects

– "All business logic should be encapsulated onto the domain objects." – "The user interface should be a direct representation of the domain objects, with all user actions explicitly consist in the creating or the retrieving of domain objects and/or invoking methods on those objects." – "The user interface shall be 100% automatically created from the definition of the domain objects."

slide-34
SLIDE 34

Naked Objects: Overview

Benefits:

– faster development cycle – greater agility – more user-centric/empowered user interface – easier requirements analysis

slide-35
SLIDE 35

Naked Objects: Basics

Understand the principles of Naked Objects

slide-36
SLIDE 36

Basics

Naked Objects frameworks core concepts

– Domain Objects

  • properties
  • collections
  • actions

– Value types – Non-objects

  • Factories/Repositories
  • services
  • external/system services

– ViewModels

slide-37
SLIDE 37

Basics

Domain objects

– domain objects represent the persistent entities described within the system – these are your "plain old objects" (POJOs, POCOs, etc) – typically they intend to represent state plus behavior

  • state is expressed as properties
  • behavior is expressed as actions
slide-38
SLIDE 38

Basics

Properties

– represents an element of state in a domain object – typically one of three types

  • value property (property of value type)
  • reference property (association to another domain object)
  • collection property (collection of properties)

– properties can have some UI logic or behavior attached to them

  • control the order in which properties are displayed
  • trigger behavior when a property is changed
  • input validation
slide-39
SLIDE 39

Basics

Actions

– actions are methods intended for user invocation – typically these are "just methods" that are discovered

slide-40
SLIDE 40

Basics

Value types

– these are basically non-referenced objects – we care only for their value – they lack a standalone "identity" – embedded "in-place" for storage

slide-41
SLIDE 41

Basics

Services

– services are code that aren't attached specifically to

  • bjects

these are often pure logic/behavior/transformational in nature

– NakedObject services come in three flavors:

  • creating/retrieving domain objects (factories/repositories)
  • provide a bridge to external functionality (external services)
  • provide functionality shared by multiple domain objects

which do not share a common superclass (contributed actions)

slide-42
SLIDE 42

Basics

Factories/respositories

– factory is a service for manufacturing new instances of an

  • bject

– repository is a service for obtaining existing instances of

  • bjects

– whether these are the same service is a point of debate

NakedObjects frameworks typically support either style

– most often, objects will be found by navigating from other

  • bjects

Pet -> Owner doesn't require the use of a repository, for example

slide-43
SLIDE 43

Basics

External services

– bridge to external functionality

such as accessing an email system to send/receive messages

– these will vary in size and shape with the external functionality being accessed/used – look to avoid duplicating Naked Object functionality here!

shouldn't need to write a database access service, for example

slide-44
SLIDE 44

Basics

Contributed actions

– a contributed action is an action that is defined on a service but which is presented to the user as an action on an individual domain object (or collection of objects) – these are, effectively, "aspect-oriented" actions applied to Naked Objects

slide-45
SLIDE 45

Getting Started

Naked Objects in Java: Apache Isis

slide-46
SLIDE 46

Getting Started

Apache Isis

– top-level apache.org project – provides a NakedObjects implementation as Web app – uses HSQL as built-in database

configurable, of course

– uses Apche Shiro for auth/auth

slide-47
SLIDE 47

Getting Started

Bootstrap the Maven archetype

– Java latest – Maven latest

slide-48
SLIDE 48

Getting Started

Build an empty Isis application

mvn archetype:generate \

  • D archetypeGroupId=org.apache.isis.archetype \
  • D archetypeArtifactId=simpleapp-archetype \
  • D archetypeVersion=1.15.0 \
  • D groupId=com.mycompany \
  • D artifactId=myapp \
  • D version=1.0-SNAPSHOT \
  • D archetypeRepository=http://repository-

estatio.forge.cloudbees.com/snapshot/ \

  • B
slide-49
SLIDE 49

Getting Started

Build and run the app

$ cd myapp $ mvn clean install $ mvn -pl webapp jetty:run

Browse to http://localhost:8080 (login w/ "sven"/"pass")

slide-50
SLIDE 50

Labs

Lab 0: Getting Started (15 minutes)

– Install Apache Isis

use the helloworld archetype

– Run the default application

default creds: "sven"/"pass"

slide-51
SLIDE 51

Domain Objects

Domain/subject entities in Apache Isis

slide-52
SLIDE 52

Isis Domain Objects

Start with "simple" O-O domain class

– identifiable and unique – natural sort order

implements Comparable<T>

– containing (some) business logic – validating rules – ... and so on

slide-53
SLIDE 53

Isis Domain Objects

Isis uses Java annotations to carry metadata

– identification of domain entities – presentation customization – persistence customization – ... and so on

slide-54
SLIDE 54

Isis Domain Objects

@DomainObject

– identifies that this class is an Isis domain object – annotation data elements control details

editing: whether the instance can be considered immutable

slide-55
SLIDE 55

Isis Domain Objects

Domain Objects

@DomainObjectLayout() @DomainObject(auditing = Auditing.ENABLED) public class Convention implements Comparable<Convention> {

slide-56
SLIDE 56

Isis Domain Objects

Properties

– typical private-field-public-getter-setter idiom – presumption is that getter and setter "do the right thing"

  • r Project Lombok Getter/Setter annotations can generate

methods

– some properties (objects that are value objects) should be @Persistent-annotated

slide-57
SLIDE 57

Isis Domain Objects

@Property annotation customizes property details

– editing: whether the instance can be considered immutable

  • bjects can still be modified, just no through the UI

– maxLength: maximum length allowed – hidden: indicates where in the UI this property should be hidden

EVERYWHERE, OBJECT_FORMS, PARENTED_TABLES, STANDALONE_TABLES, ALL_TABLES, NOWHERE

– regexPattern/regexPatternFlags: regular expression for validation

slide-58
SLIDE 58

Isis Domain Objects

Domain Objects

@javax.jdo.annotations.Column(allowsNull = "false", length = 40) @lombok.NonNull @Property(editing = Editing.DISABLED) @Title(prepend = "Convention: ") @MemberOrder(sequence="1") private String name; public String getName() { return this.name; } public void setName(String val) { this.name = val; }

slide-59
SLIDE 59

Isis Domain Objects

Domain Objects

@javax.jdo.annotations.Persistent @javax.jdo.annotations.Column(allowsNull = "true") @Property(editing = Editing.ENABLED) @MemberOrder(name="Dates", sequence="1") private LocalDate start; public LocalDate getStart() { return this.start; } public void setStart(LocalDate val) { this.start = val; // calculate some reasonable values for the other dates } public String validateStart(LocalDate proposed) { // validate the start date is in the future (from now) return null; }

slide-60
SLIDE 60

Isis Domain Objects

Properties can be validated

– "validate{propertyName}()" methods – returns a String

  • String contents contain message for validation failure
  • or return null for acceptance

– see "Classes, Methods, Schema" documentation for full list

slide-61
SLIDE 61

Isis Domain Objects

Actions

– typical public method – presumption is that the method does not represent a property or collection – actions often used to allow for restricted editing – actions also often create objects from menu options

slide-62
SLIDE 62

Isis Domain Objects

@Action annotation used to customize actions

– restrictTo: whether the action is available in production or just prototyping

NO_RESTRICTIONS,PROTOTYPING

– semantics: provide UI hints about the action's semantics

SAFE_AND_REQUEST_CACHEABLE, SAFE, IDEMPOTENT, IDEMPOTENT_ARE_YOU_SURE, NON_IDEMPOTENT, NON_IDEMPOTENT_ARE_YOU_SURE

– typeOf: type of objects returned from a collection

as a fallback

slide-63
SLIDE 63

Isis Domain Objects

Domain Objects

@Action(semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE) public void delete() { final String title = titleService.titleOf(this); messageService.informUser(String.format("'%s' deleted", title)); repositoryService.removeAndFlush(this); }

slide-64
SLIDE 64

Isis Domain Objects

Dependent services are injected

– use the javax.inject.Inject annotation to annotate the field – typically the domain object's repository is injected – other services as need demands

slide-65
SLIDE 65

Isis Domain Objects

Domain Objects

@javax.inject.Inject @lombok.Getter(AccessLevel.NONE) @lombok.Setter(AccessLevel.NONE) EventRepository eventRepo; @javax.inject.Inject @lombok.Getter(AccessLevel.NONE) @lombok.Setter(AccessLevel.NONE) RepositoryService repositoryService; @javax.inject.Inject @lombok.Getter(AccessLevel.NONE) @lombok.Setter(AccessLevel.NONE) MessageService messageService; @javax.inject.Inject @lombok.Getter(AccessLevel.NONE) @lombok.Setter(AccessLevel.NONE) TitleService titleService;

slide-66
SLIDE 66

Isis Domain Objects

Presentation is derived from class

– @DomainObjectLayout annotation can control UI aspects – @MemberOrder controls the order of appearance of properties in the table

name defines grouping ("General" by default), sequence defines order

– @MemberGroupLayout controls the layout of groups of members – object menus derived from actions present on the object – More sophisticated layout can be done via a DomainObject.layout.xml file

initial versions of these can be downloaded from the prototyping UI

slide-67
SLIDE 67

Isis Domain Objects

Presentation "hints" can come elsewhere

– title() method returns full object title

  • r use @Title to mark which properties provide title

– choices{name}() method(s) returns list of UI choices – autoComplete{name}() provides auto-complete UI behavior – disable{name}() determines whether to disable UI element – hide{name}() determines whether to hide UI element

slide-68
SLIDE 68

Isis Domain Objects

Presentation "hints" can come elsewhere

– cssClass() returns CSS class to use

@ActionLayout(), @PropertyLayout or @CollectionLayout can specify CSS to use per-element

– iconName() returns icon (file) name to use

slide-69
SLIDE 69

Isis Domain Objects

Object lifecycle

– transient v persistent

  • objects begin as transient until persisted
  • create objects using container.newTransientInstance(T.class)

– programmatically save using container.persist()

  • nce saved, objects save themselves henceforth
slide-70
SLIDE 70

Isis Domain Objects

Persistence is handled by JDO

– using the DataNucleus JDO classfile enhancer

  • uses JDO annotations to control schema and queries
  • does bytecode enhancement at compile-time

– by default, runs in-memory H2 database

  • bviously can be configured to use any JDBC database
slide-71
SLIDE 71

Isis Domain Objects

JDO class annotations

– @PersistenceCapable: the class can/should be stored

  • identityType: How do we want to track identity?
  • schema: What schema does this type belong in?

– @DatastoreIdentity: what's the strategy we want to use for OIDs?

  • strategy: the strategy (enumeration) to use
  • column: the column in which to store the identity
  • IdentityType.DATASTORE and "id" are the usual values here

– @Version: how do we want to track instance differences?

  • strategy: the strategy (enumeration) to use
  • column: the column in which to track the differences
  • VersionStrategy.DATE_TIME and "version" are the usual

values here

slide-72
SLIDE 72

Isis Domain Objects

JDO class annotations

– @Queries: defining queries that can be invoked

  • this is an array of Query annotations
  • each Query annotation has a "name" and "value" (being the

query text)

  • this is JDOQL, not SQL (which are very similar in syntax)

– @Unique: defining uniqueness constraints on the class/table

slide-73
SLIDE 73

Isis Domain Objects

Domain Objects

@javax.jdo.annotations.PersistenceCapable( identityType = IdentityType.DATASTORE, schema = "dragonflight" ) @javax.jdo.annotations.DatastoreIdentity( strategy = IdGeneratorStrategy.IDENTITY, column = "id") @javax.jdo.annotations.Version( strategy= VersionStrategy.DATE_TIME, column ="version") @javax.jdo.annotations.Queries({ @javax.jdo.annotations.Query( name = "findByName", value = "SELECT " + "FROM domainapp.dom.impl.Convention " + "WHERE name.indexOf(:name) >= 0 ") }) @javax.jdo.annotations.Unique(name="Convention_name_UNQ", members = {"name"}) // Should have a query that finds the upcoming one (by date)

slide-74
SLIDE 74

Isis Domain Objects

JDO field annotations

– @Column: describes the column-storage details for this field

  • allowsNull (boolean): can we store without a value here?
  • length (int): storage size of the column (characters)

– @Persistent: indication that the non-primitive field should be stored as a "dependent" value

meaning, a value object with no identity of its own

slide-75
SLIDE 75

Isis Domain Objects

Object lifecycle methods

– created()

called when an object has just been created using newTransientInstance()

– loaded()

called when a (persistent) object has just been loaded from the object store.

– persisted()

called when object has just been persisted from the object store.

– persisting()

called when a (not-yet-persistent) object is just about to be persisted from the object store

slide-76
SLIDE 76

Isis Domain Objects

Object lifecycle methods

– removed()

called when a (persistent) object has just been deleted from the object store

– removing()

called when a (persistent) object is just about to be deleted from the object store

– updated()

called when a (persistent) object has just been updated in the

  • bject store

– updating()

called when a (persistent) object is just about to be updated in the object store

slide-77
SLIDE 77

Services

Naked services in Apache Isis

slide-78
SLIDE 78

Services

Services are "just" domain objects

– they represent behaviors, not state – they frequently provide entrypoints into the system

such as creating objects

– or they provide access outside of the system

slide-79
SLIDE 79

Services

Isis-provided services

– ClockService – ConfigurationService – MessageService – RepositoryService – ServiceRegistry – TitleService – UserService

slide-80
SLIDE 80

Services

Isis-provided services

– EventBusService – EmailService – AuditerService – BackgroundService – ... and a lot more

slide-81
SLIDE 81

Services

Despite that, you will want to write your own services

– repository services

for creating and finding domain entities

– shared behavior services

behavior that should be shared across non-related domain entities

– "external access" services

behavior to access external systems not already provided by Isis

slide-82
SLIDE 82

Services

Services are "just" domain objects

– @DomainService annotation helps discoverability

  • nature parameter describes the "visibility" of this service
  • VIEW_MENU_ONLY: only appear in the GUI
  • VIEW_REST_ONLY: only appear in the Restful Objects viewer
  • DOMAIN: only for programmatic use; don't show in UI
slide-83
SLIDE 83

Services

Presentation

– By default each domain service corresponds to a single menu item on the menu bar – @DomainServiceLayout can control the grouping and layout

  • "primary menu" is the leftmost grouping in the top menubar
  • "secondary menu" is the rightmost grouping in the top

menubar

  • "tertiary menu" is a menu under the user's name in the

upper-right corner

slide-84
SLIDE 84

Labs

Lab 1a: Basic domain entities (60 mins)

– Create domainapp.dom.impl.Customer (domain entity)

  • firstName, lastName, street, city, postCode
  • just do simple getters/setters for now

– Create domainapp.dom.impl.CustomerRepository (domain service)

create(String fn, String ln), findByLastName(), listAll() (prototyping only)

– Hint: You can use HelloWorldObject/HelloWorldObjects as an exemplar – Run the app to test

mvn jetty:run

slide-85
SLIDE 85

Labs

Lab 1b: Basic domain entities (45 mins)

– Make sure nobody lives on "Sassafrass" street

use validateStreet() to prevent this

– Group the fields into two groups

  • "General" (firstName, lastName)
  • "Address" (street / city / postCode)
  • use the @MemberOrder and @MemberGroupLayout

annotation

– Make sure the fields are editable

look at the @Property annotation

slide-86
SLIDE 86

Domain object associations

Modeling object relationships in Apache Isis

slide-87
SLIDE 87

Associations

Modeling associations in Isis

– mostly a JDO concern

table-to-table relationships

– typically modeled in code using java Collections

recommended to use SortedSet, since that fits the model most closely

slide-88
SLIDE 88

Associations

1:m (parent-child) associations

– parent class holds a SortedSet-of-Child field

  • annotate with @Persistent
  • mappedBy = parent field name in Child
  • dependentElement = support cascade deletes?

– child class holds a Parent field

  • annotate with @Column
  • allowsNull = true (mandatory) or false (optional)

– build the connection by setting the parent in the child

slide-89
SLIDE 89

Associations

Parent

public class Parent { // getters and setters omitted @Persistent(mappedBy = "batch", dependentElement = "false") private SortedSet<Child> children = new TreeSet<Child>(); public Parent adoptChild(final Child child) { child.setParent(this); return this; } }

Child

public class Child { // getters and setters omitted @Column(allowNulls = false) private Parent batch; }

slide-90
SLIDE 90

Labs

Lab 2: Associations (45 mins)

– "A Customer can have many Orders" – Create domainapp.dom.impl.Order (domain entity)

placed (LocalDateTime), delivery (LocalDateTime), totalAmount (int)

– Define the parent/child relationship from Customer to Order

  • Customer (parent)
  • Order (child)
  • mandatory, and cascading delete

– Add an @Action to Customer to "Place Order"

  • two parameters (amount, delivery)
  • use the RepositoryService to construct the Order
  • use the ClockService to get the current date/time and set

that as the value for "placed"

slide-91
SLIDE 91

Naked Objects: Resources

Where to go for more information/ideas/etc

slide-92
SLIDE 92

Resources

Reading

– Richard Pawson's PhD thesis

http://downloads.nakedobjects.net/resources/Pawson%20th esis.pdf

– "Naked Objects"

http://www.nakedobjects.org/book/

– "DDD Using Naked Objects", by Dan Haywood (Pragmatic Bookshelf)

http://www.pragprog.com/titles/dhnako/domain-driven- design-using-naked-objects