SlideShare una empresa de Scribd logo
1 de 94
Descargar para leer sin conexión
Don’t Settle for
Poor Names
Alistair McKinnell
@amckinnell
1974
Naming
is deeply

connected to
Designing
Designing
is deeply

connected to
Naming
Example from

QCloud
QCloud has forms,

sheets, and inspections
QCloud has forms,

sheets, and inspections
A sheet is composed of a
reviewed and a submitted
{ something or other }
class Sheet < ActiveRecord::Base
class Sheet < ActiveRecord::Base
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
class Sheet < ActiveRecord::Base
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
class Sheet < ActiveRecord::Base
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
class Sheet < ActiveRecord::Base
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
A sheet is composed of a
reviewed and a submitted
{ something or other }
A sheet is composed of a
reviewed and a submitted
attribution event
An attribution event
identifies a user and

has a timestamp
An attribution event
identifies a user and

has a timestamp
An attribution event
identifies a user and

has a timestamp
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
An attribution event
identifies a user and

has a timestamp
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
sheet.submitted_attribution_event =
AttributionEvent.new(
inspector.name, inspector.email,
inspector.id, Time.zone.now
)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
sheet.submitted_attribution_event =
AttributionEvent.new(
inspector.name, inspector.email,
inspector.id, Time.zone.now
)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
An attribution event
identifies a user and

has a timestamp
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def self.build(user, at: Time.zone.now)
new(user.name, user.email, user.id, at)
end
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
An attribution event
identifies a user and

has a timestamp
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
!
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = reviewer.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
!
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = reviewer.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
After
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def self.build(user, at: Time.zone.now)
new(user.name, user.email, user.id, at)
end
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
class Sheet < ActiveRecord::Base
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
class Sheet < ActiveRecord::Base
composed_of :reviewed_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
[‘reviewed_by_name’, 'name'],
[‘reviewed_by_email', 'email'],
[‘reviewed_by_id', 'user_id'],
[‘reviewed_at', 'event_at']
]
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
[‘submitted_by_name', 'name'],
[‘submitted_by_email’, 'email'],
[‘submitted_by_id', 'user_id'],
[‘submitted_at’, 'event_at']
]
class Sheet < ActiveRecord::Base
attribution_event :reviewed
attribution_event :submitted
class Sheet < ActiveRecord::Base
attribution_event :reviewed
attribution_event :submitted
attribution_event :discarded
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
composed_of :reviewed_attribution_event,
class_name :'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
Before
include Models::AttributionEvents
attribution_event :reviewed
composed_of :reviewed_attribution_event,
class_name :'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
Before
After
include Models::AttributionEvents
attribution_event :reviewed
composed_of :reviewed_attribution_event,
class_name :'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
Before
After
An attribution event
identifies a user and

has a timestamp
And there are different 

types of attribution events
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.reviewed_attribution_event =
AttributionEvent.build(supervisor)
class Sheet < ActiveRecord::Base
include Models::AttributionEvents
attribution_event :reviewed
attribution_event :submitted
...
end
sheet.submitted_attribution_event =
AttributionEvent.build(inspector)
sheet.reviewed_attribution_event =
AttributionEvent.build(supervisor)
class Sheet < ActiveRecord::Base
include Models::AttributionEvents
attribution_event :reviewed
attribution_event :submitted
...
end
How do we { log, capture,
assign, save, or record }
an attribution event ?
sheet.log_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
sheet.capture_attribution_event(
type: :submitted, user: inspector, at: submitted_at
)
header.assign_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
inspection.save_attribution_event(
type: :submitted, user: inspector, at: reviewed_at
)
inspection.record_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
sheet.log_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
sheet.capture_attribution_event(
type: :submitted, user: inspector, at: submitted_at
)
header.assign_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
inspection.save_attribution_event(
type: :submitted, user: inspector, at: reviewed_at
)
inspection.record_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
sheet.log_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
sheet.capture_attribution_event(
type: :submitted, user: inspector, at: submitted_at
)
sheet.assign_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
inspection.save_attribution_event(
type: :submitted, user: inspector, at: reviewed_at
)
sheet.record_attribution_event(
type: :reviewed, user: inspector, at: reviewed_at
)
module Models
module AttributionEvents
extend ActiveSupport::Concern
included do
def capture_attribution_event(type:, user:,
at: Time.zone.now)
send("#{type}_attribution_event=",
AttributionEvent.build(user, at: at))
end
end
module ClassMethods
...
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
included do
def capture_attribution_event(type:, user:,
at: Time.zone.now)
send("#{type}_attribution_event=",
AttributionEvent.build(user, at: at))
end
end
module ClassMethods
...
end
end
end
module Models
module AttributionEvents
extend ActiveSupport::Concern
included do
def capture_attribution_event(type:, user:,
at: Time.zone.now)
send("#{type}_attribution_event=",
AttributionEvent.build(user, at: at))
end
end
module ClassMethods
...
end
end
end
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Before
sheet.capture_attribution_event(
type: :submitted, user: inspector
)
Before
After
sheet.submitted_by_name = inspector.name
sheet.submitted_by_email = inspector.email
sheet.submitted_by_id = inspector.id
sheet.submitted_at = Time.zone.now
Example from

QCloud
composed_of Concern
An attribution event
identifies a user and

has a timestamp
And we capture different 

types of attribution events
class Sheet < ActiveRecord::Base
include Models::AttributionEvents
attribution_event :reviewed
attribution_event :submitted
sheet.capture_attribution_event(
type: :submitted, user: inspector
)
An attribution event
identifies a user and

has a timestamp
And we capture different 

types of attribution events
class Sheet < ActiveRecord::Base
include Models::AttributionEvents
attribution_event :reviewed
attribution_event :submitted
sheet.capture_attribution_event(
type: :submitted, user: inspector
)
Naming
is deeply

connected to
Designing
Designing
is deeply

connected to
Naming
Ubiquitous 

Language
The language used by everyone on the team
to describe the domain model when speaking,
writing user stories, and in the source code.
• Passes the tests
• Reveals intention
Simple 

Design
• No duplication
• Fewest elements
Simple 

Design
• Removes duplication
• Improves names
The Simple Design Dynamo™
Example from

QCloud
class Sheet < ActiveRecord::Base
composed_of :reviewed_attribution_event,
class_name: 'AttributionEvent',
allow_nil: true,
mapping: [
['reviewed_by_name', 'name'],
['reviewed_by_email', 'email'],
['reviewed_by_id', 'user_id'],
['reviewed_at', 'event_at']
]
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
['submitted_by_name', 'name'],
['submitted_by_email', 'email'],
['submitted_by_id', 'user_id'],
['submitted_at', 'event_at']
]
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
sheet.submitted_attribution_event =
AttributionEvent.new(
inspector.name, inspector.email,
inspector.id, Time.zone.now
)
#
# Represents the information required to attribute
# an event to a user.
#
class AttributionEvent
attr_reader :name, :email, :user_id, :event_at
def self.build(user, at: Time.zone.now)
new(user.name, user.email, user.id, at)
end
def initialize(name, email, user_id, at)
@name = name
@email = email
@user_id = user_id
@event_at = at
end
end
An attribution event
identifies a user and

has a timestamp
class Sheet < ActiveRecord::Base
composed_of :reviewed_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
[‘reviewed_by_name’, 'name'],
[‘reviewed_by_email', 'email'],
[‘reviewed_by_id', 'user_id'],
[‘reviewed_at', 'event_at']
]
composed_of :submitted_attribution_event,
class_name: ’AttributionEvent',
allow_nil: true,
mapping: [
[‘submitted_by_name', 'name'],
[‘submitted_by_email’, 'email'],
[‘submitted_by_id', 'user_id'],
[‘submitted_at’, 'event_at']
]
module Models
module AttributionEvents
extend ActiveSupport::Concern
module ClassMethods
def attribution_event(type, allow_nil: true)
attribution_event = <<-ATTRIBUTION_EVENT
composed_of :#{type}_attribution_event,
class_name: 'AttributionEvent',
allow_nil: #{allow_nil},
mapping: [
['#{type}_by_name', 'name'],
['#{type}_by_email', 'email'],
['#{type}_by_id', 'user_id'],
['#{type}_at', 'event_at']
]
ATTRIBUTION_EVENT
class_eval(attribution_event)
end
end
end
end
class Sheet < ActiveRecord::Base
include Models::AttributionEvents
attribution_event :reviewed
attribution_event :submitted
sheet.capture_attribution_event(
type: :submitted, user: inspector
)
sheet.capture_attribution_event(
type: :reviewed, user: supervisor
)
The Simple Design Dynamo™
Don’t Settle for
Poor Names
Don’t Settle for
Poor Names
Pretty Please
Don't Settle for Poor Names in Software

Más contenido relacionado

Similar a Don't Settle for Poor Names in Software

Sending Email with Rails
Sending Email with RailsSending Email with Rails
Sending Email with RailsJames Gray
 
Web technology javascript
Web technology   javascriptWeb technology   javascript
Web technology javascriptUma mohan
 
Ajax nested form and ajax upload in rails
Ajax nested form and ajax upload in railsAjax nested form and ajax upload in rails
Ajax nested form and ajax upload in railsTse-Ching Ho
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreRyan Weaver
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Endpoint node.js framework presentation
Endpoint node.js framework presentationEndpoint node.js framework presentation
Endpoint node.js framework presentationabresas
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weiboshaokun
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityRyan Weaver
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Luka Zakrajšek
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Implementation of EAV pattern for ActiveRecord models
Implementation of EAV pattern for ActiveRecord modelsImplementation of EAV pattern for ActiveRecord models
Implementation of EAV pattern for ActiveRecord modelsKostyantyn Stepanyuk
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
Empower your App by Inheriting from Odoo Mixins
Empower your App by Inheriting from Odoo MixinsEmpower your App by Inheriting from Odoo Mixins
Empower your App by Inheriting from Odoo MixinsOdoo
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails Mohit Jain
 
Creating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdfCreating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdfShaiAlmog1
 

Similar a Don't Settle for Poor Names in Software (20)

Sending Email with Rails
Sending Email with RailsSending Email with Rails
Sending Email with Rails
 
Web technology javascript
Web technology   javascriptWeb technology   javascript
Web technology javascript
 
Ajax nested form and ajax upload in rails
Ajax nested form and ajax upload in railsAjax nested form and ajax upload in rails
Ajax nested form and ajax upload in rails
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Endpoint node.js framework presentation
Endpoint node.js framework presentationEndpoint node.js framework presentation
Endpoint node.js framework presentation
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Implementation of EAV pattern for ActiveRecord models
Implementation of EAV pattern for ActiveRecord modelsImplementation of EAV pattern for ActiveRecord models
Implementation of EAV pattern for ActiveRecord models
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
Empower your App by Inheriting from Odoo Mixins
Empower your App by Inheriting from Odoo MixinsEmpower your App by Inheriting from Odoo Mixins
Empower your App by Inheriting from Odoo Mixins
 
CakePHP workshop
CakePHP workshopCakePHP workshop
CakePHP workshop
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
Creating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdfCreating a Facebook Clone - Part XIV - Transcript.pdf
Creating a Facebook Clone - Part XIV - Transcript.pdf
 

Más de Alistair McKinnell

Succeeding with Specification by Example
Succeeding with Specification by ExampleSucceeding with Specification by Example
Succeeding with Specification by ExampleAlistair McKinnell
 
What Can Journalists Teach Developers About Writing Source Code?
What Can Journalists Teach Developers About Writing Source Code?What Can Journalists Teach Developers About Writing Source Code?
What Can Journalists Teach Developers About Writing Source Code?Alistair McKinnell
 
Commonality and Variability Analysis: Avoiding Duplicate Code
Commonality and Variability Analysis: Avoiding Duplicate CodeCommonality and Variability Analysis: Avoiding Duplicate Code
Commonality and Variability Analysis: Avoiding Duplicate CodeAlistair McKinnell
 
Agile Tour Shanghai December 2011
Agile Tour Shanghai December 2011Agile Tour Shanghai December 2011
Agile Tour Shanghai December 2011Alistair McKinnell
 
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic ToolAgile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic ToolAlistair McKinnell
 
Struggling to Create Maintainable Unit Tests?
Struggling to Create Maintainable Unit Tests?Struggling to Create Maintainable Unit Tests?
Struggling to Create Maintainable Unit Tests?Alistair McKinnell
 

Más de Alistair McKinnell (13)

Succeeding with Specification by Example
Succeeding with Specification by ExampleSucceeding with Specification by Example
Succeeding with Specification by Example
 
The Boy Scout Rule
The Boy Scout RuleThe Boy Scout Rule
The Boy Scout Rule
 
Advanced Developer Testing
Advanced Developer TestingAdvanced Developer Testing
Advanced Developer Testing
 
What Can Journalists Teach Developers About Writing Source Code?
What Can Journalists Teach Developers About Writing Source Code?What Can Journalists Teach Developers About Writing Source Code?
What Can Journalists Teach Developers About Writing Source Code?
 
Ubiquitous Testing
Ubiquitous TestingUbiquitous Testing
Ubiquitous Testing
 
Commonality and Variability Analysis: Avoiding Duplicate Code
Commonality and Variability Analysis: Avoiding Duplicate CodeCommonality and Variability Analysis: Avoiding Duplicate Code
Commonality and Variability Analysis: Avoiding Duplicate Code
 
Simple Design
Simple DesignSimple Design
Simple Design
 
Agile Tour Shanghai December 2011
Agile Tour Shanghai December 2011Agile Tour Shanghai December 2011
Agile Tour Shanghai December 2011
 
Pair Programming
Pair ProgrammingPair Programming
Pair Programming
 
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic ToolAgile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
 
The Story of a Story
The Story of a StoryThe Story of a Story
The Story of a Story
 
The Testing Landscape
The Testing LandscapeThe Testing Landscape
The Testing Landscape
 
Struggling to Create Maintainable Unit Tests?
Struggling to Create Maintainable Unit Tests?Struggling to Create Maintainable Unit Tests?
Struggling to Create Maintainable Unit Tests?
 

Último

Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 

Último (20)

Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 

Don't Settle for Poor Names in Software

  • 1. Don’t Settle for Poor Names Alistair McKinnell @amckinnell
  • 3.
  • 4.
  • 5.
  • 6.
  • 10. QCloud has forms,
 sheets, and inspections
  • 11. QCloud has forms,
 sheets, and inspections
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18. A sheet is composed of a reviewed and a submitted { something or other }
  • 19.
  • 20.
  • 21. class Sheet < ActiveRecord::Base
  • 22. class Sheet < ActiveRecord::Base composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ]
  • 23. class Sheet < ActiveRecord::Base composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ] composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ]
  • 24. class Sheet < ActiveRecord::Base composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ] composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ]
  • 25. class Sheet < ActiveRecord::Base composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ] composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ]
  • 26. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ]
  • 27. A sheet is composed of a reviewed and a submitted { something or other }
  • 28. A sheet is composed of a reviewed and a submitted attribution event
  • 29. An attribution event identifies a user and
 has a timestamp
  • 30. An attribution event identifies a user and
 has a timestamp
  • 31. An attribution event identifies a user and
 has a timestamp
  • 32. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end An attribution event identifies a user and
 has a timestamp
  • 33. sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before
  • 34. sheet.submitted_attribution_event = AttributionEvent.new( inspector.name, inspector.email, inspector.id, Time.zone.now ) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After
  • 35. sheet.submitted_attribution_event = AttributionEvent.new( inspector.name, inspector.email, inspector.id, Time.zone.now ) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After
  • 36. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end An attribution event identifies a user and
 has a timestamp
  • 37. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def self.build(user, at: Time.zone.now) new(user.name, user.email, user.id, at) end def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end An attribution event identifies a user and
 has a timestamp
  • 38. sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before
  • 39. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After
  • 40. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.submitted_by_name = inspector.name sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After !
  • 41. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After
  • 42. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = reviewer.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After !
  • 43. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.submitted_by_name = inspector.name sheet.submitted_by_email = reviewer.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before After
  • 44. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def self.build(user, at: Time.zone.now) new(user.name, user.email, user.id, at) end def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end
  • 45. class Sheet < ActiveRecord::Base composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ] composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ]
  • 46. class Sheet < ActiveRecord::Base composed_of :reviewed_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ [‘reviewed_by_name’, 'name'], [‘reviewed_by_email', 'email'], [‘reviewed_by_id', 'user_id'], [‘reviewed_at', 'event_at'] ] composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ [‘submitted_by_name', 'name'], [‘submitted_by_email’, 'email'], [‘submitted_by_id', 'user_id'], [‘submitted_at’, 'event_at'] ]
  • 47. class Sheet < ActiveRecord::Base attribution_event :reviewed attribution_event :submitted
  • 48. class Sheet < ActiveRecord::Base attribution_event :reviewed attribution_event :submitted attribution_event :discarded
  • 49.
  • 50.
  • 51. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 52. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 53. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 54. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 55. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 56. composed_of :reviewed_attribution_event, class_name :'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ] Before
  • 57. include Models::AttributionEvents attribution_event :reviewed composed_of :reviewed_attribution_event, class_name :'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ] Before After
  • 58. include Models::AttributionEvents attribution_event :reviewed composed_of :reviewed_attribution_event, class_name :'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ] Before After
  • 59. An attribution event identifies a user and
 has a timestamp And there are different 
 types of attribution events
  • 60. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.reviewed_attribution_event = AttributionEvent.build(supervisor) class Sheet < ActiveRecord::Base include Models::AttributionEvents attribution_event :reviewed attribution_event :submitted ... end
  • 61. sheet.submitted_attribution_event = AttributionEvent.build(inspector) sheet.reviewed_attribution_event = AttributionEvent.build(supervisor) class Sheet < ActiveRecord::Base include Models::AttributionEvents attribution_event :reviewed attribution_event :submitted ... end
  • 62. How do we { log, capture, assign, save, or record } an attribution event ?
  • 63. sheet.log_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) sheet.capture_attribution_event( type: :submitted, user: inspector, at: submitted_at ) header.assign_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) inspection.save_attribution_event( type: :submitted, user: inspector, at: reviewed_at ) inspection.record_attribution_event( type: :reviewed, user: inspector, at: reviewed_at )
  • 64. sheet.log_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) sheet.capture_attribution_event( type: :submitted, user: inspector, at: submitted_at ) header.assign_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) inspection.save_attribution_event( type: :submitted, user: inspector, at: reviewed_at ) inspection.record_attribution_event( type: :reviewed, user: inspector, at: reviewed_at )
  • 65. sheet.log_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) sheet.capture_attribution_event( type: :submitted, user: inspector, at: submitted_at ) sheet.assign_attribution_event( type: :reviewed, user: inspector, at: reviewed_at ) inspection.save_attribution_event( type: :submitted, user: inspector, at: reviewed_at ) sheet.record_attribution_event( type: :reviewed, user: inspector, at: reviewed_at )
  • 66. module Models module AttributionEvents extend ActiveSupport::Concern included do def capture_attribution_event(type:, user:, at: Time.zone.now) send("#{type}_attribution_event=", AttributionEvent.build(user, at: at)) end end module ClassMethods ... end end end
  • 67. module Models module AttributionEvents extend ActiveSupport::Concern included do def capture_attribution_event(type:, user:, at: Time.zone.now) send("#{type}_attribution_event=", AttributionEvent.build(user, at: at)) end end module ClassMethods ... end end end
  • 68. module Models module AttributionEvents extend ActiveSupport::Concern included do def capture_attribution_event(type:, user:, at: Time.zone.now) send("#{type}_attribution_event=", AttributionEvent.build(user, at: at)) end end module ClassMethods ... end end end
  • 69. sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now Before
  • 70. sheet.capture_attribution_event( type: :submitted, user: inspector ) Before After sheet.submitted_by_name = inspector.name sheet.submitted_by_email = inspector.email sheet.submitted_by_id = inspector.id sheet.submitted_at = Time.zone.now
  • 72. An attribution event identifies a user and
 has a timestamp And we capture different 
 types of attribution events
  • 73. class Sheet < ActiveRecord::Base include Models::AttributionEvents attribution_event :reviewed attribution_event :submitted sheet.capture_attribution_event( type: :submitted, user: inspector ) An attribution event identifies a user and
 has a timestamp And we capture different 
 types of attribution events
  • 74. class Sheet < ActiveRecord::Base include Models::AttributionEvents attribution_event :reviewed attribution_event :submitted sheet.capture_attribution_event( type: :submitted, user: inspector )
  • 77.
  • 78. Ubiquitous 
 Language The language used by everyone on the team to describe the domain model when speaking, writing user stories, and in the source code.
  • 79. • Passes the tests • Reveals intention Simple 
 Design • No duplication • Fewest elements
  • 80. Simple 
 Design • Removes duplication • Improves names
  • 81. The Simple Design Dynamo™
  • 83.
  • 84. class Sheet < ActiveRecord::Base composed_of :reviewed_attribution_event, class_name: 'AttributionEvent', allow_nil: true, mapping: [ ['reviewed_by_name', 'name'], ['reviewed_by_email', 'email'], ['reviewed_by_id', 'user_id'], ['reviewed_at', 'event_at'] ] composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ ['submitted_by_name', 'name'], ['submitted_by_email', 'email'], ['submitted_by_id', 'user_id'], ['submitted_at', 'event_at'] ]
  • 85. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end sheet.submitted_attribution_event = AttributionEvent.new( inspector.name, inspector.email, inspector.id, Time.zone.now )
  • 86. # # Represents the information required to attribute # an event to a user. # class AttributionEvent attr_reader :name, :email, :user_id, :event_at def self.build(user, at: Time.zone.now) new(user.name, user.email, user.id, at) end def initialize(name, email, user_id, at) @name = name @email = email @user_id = user_id @event_at = at end end An attribution event identifies a user and
 has a timestamp
  • 87. class Sheet < ActiveRecord::Base composed_of :reviewed_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ [‘reviewed_by_name’, 'name'], [‘reviewed_by_email', 'email'], [‘reviewed_by_id', 'user_id'], [‘reviewed_at', 'event_at'] ] composed_of :submitted_attribution_event, class_name: ’AttributionEvent', allow_nil: true, mapping: [ [‘submitted_by_name', 'name'], [‘submitted_by_email’, 'email'], [‘submitted_by_id', 'user_id'], [‘submitted_at’, 'event_at'] ]
  • 88. module Models module AttributionEvents extend ActiveSupport::Concern module ClassMethods def attribution_event(type, allow_nil: true) attribution_event = <<-ATTRIBUTION_EVENT composed_of :#{type}_attribution_event, class_name: 'AttributionEvent', allow_nil: #{allow_nil}, mapping: [ ['#{type}_by_name', 'name'], ['#{type}_by_email', 'email'], ['#{type}_by_id', 'user_id'], ['#{type}_at', 'event_at'] ] ATTRIBUTION_EVENT class_eval(attribution_event) end end end end
  • 89.
  • 90. class Sheet < ActiveRecord::Base include Models::AttributionEvents attribution_event :reviewed attribution_event :submitted sheet.capture_attribution_event( type: :submitted, user: inspector ) sheet.capture_attribution_event( type: :reviewed, user: supervisor )
  • 91. The Simple Design Dynamo™
  • 93. Don’t Settle for Poor Names Pretty Please