sand piles and software - madison ruby conference
DESCRIPTION
This is a slightly varied version my previous Sand Piles and Software talk for the Madison Ruby Conference. Instead of including slides on the values, it incorporates a second part which is dedicated to decision making and some concrete areas where we can learn to help improve how we make decisions with code.TRANSCRIPT
Sand Piles and
Software
Zach Dennis
Part I
Bak-Tang-Wiesenfeld
Sand Pile Model
macro
from themicro
What eventually happens if you keep dropping grains of
sand?
Itla
ndslid
es.
Systems can only sustain so much stress.
self-organized criticalityA property of a system that has a critical
state (point) as an attractor.
Software is attracted to its critical point.
critical point
Functionality
Com
plex
ity
Xsoftware is not linear
Software is attracted to its critical point.
critical point
Functionality
Com
plex
ity
software is non-linear
Software feeds back into itselfSx = ... (Sx - 1)
0.2 compared to 0.2000000001
critical point
Functionality
Com
plex
ity
What we don’t want.
Balanced and Distributed
Sand Piles and Sand Boxes
The Vicious Stop n Go.
Vicious Stop / Go Cycle
critical point
Functionality
Com
plex
ity
The Vicious Stop n Go.
More effort initially.
critical point
Functionality
Com
plex
ity
The Vicious Stop n Go.
Smaller apps get away with it.
critical point
Functionality
Com
plex
ity
small app large app
Performance = Complexity(Process) * Team * Tools
bad processes amplify complexity
good processes dampen it
How do we keep software away from its critical point?
Part II
Optimized decision making
pathways
def solve_problem(problem, knowledge) if quick_fix(problem).possible? quick_fix.go! else solve_problem problem, learn(problem) endend
Problem Understanding
RandomAttempts Quick fix Intentional Nailed it
None LittleGood
Amount A lot
Solution
If you do ______________ today,you’ll likely do ___________ tomorrow.
If you don’t do ______________ today,you’ll likely won’t do ___________ tomorrow.
Our brains don’t compute probabilitiesand then choose the best possible outcome
when it can avoid it.
DailyCheeper#cheep!
File System
Person Subscription
Mobile Push Library - know about where and how to load cheeps
data- know about how person is related to - know about subscriptions- know about time zone conversion- know about about to use mobile push library- localizations???
Cheeps Data
Structure
Dependencies
DailyCheeper#cheep!
Person Subscription
Mobile Push Library
- knows how to use cheeps data
- knows how to use Person interface to find eligible subscribers
- knows how to use mobile push library
Cheeps File System
- message_for_day- localization for accessing cheeps
- knows how to determine eligibility based on subscription
Dependencies after balancing responsibilities
Let’s improve our decision pathways
Domain complexity
Conceptual complexity
Code complexity
Properties and conceptsfor practical application
CohesionCouplingConnassenceEntanglement
Exposing Crisp Abstractions / ConceptsTestability
Responsibility / Dependencies / Collaborators / Boundaries
Composition InheritanceMixins
Naming, ConceptsShared UnderstandingPattern Language
Reflection
the focus of an individual software component given its function or purpose to exist
Cohesion
Array#pushArray#popArray#[]Array#countArray#<<
Cheeper#delivery_dailyCheeper#delivery_weeklyCheeper#deliver_monthly
Cheeps#loadCheeps#addCheeps#saveCheeps#remove
Not very cohesive
Separating out concepts
The relationship between software components, the extent to which a component of our software depends
on other components.
Coupling
DailyCheeper#cheep!
File System
Person Subscription
Mobile Push Library
Cheeps Data
Structure
a single measure combining coupling and cohesion, measured in terms of strength or weakness (preferred)
Connassence
Name
Type
Meaning
Position
Algorithm
Execution
Timing
Identity http://onestepback.org/articles/connascence/index.html
http://vimeo.com/10837903
http://en.wikipedia.org/wiki/Connascent_software_components
weaker
stronger
Making concepts and abstractions in your application (technical or domain related) first-class citizens.
Being explicit
Extracting a Concept w/a distinct responsibility
https://github.com/raganwald/homoiconic/blob/master/2009-10-08/metalinguistic.md
Explicit abstractions
Rake
ActiveModel::Validations
ActiveRecord::Relation
ActionController filters (orthogonality)
Whenever (gem)
Capybara
http://en.wikipedia.org/wiki/Directed_acyclic_graph
Directed Acyclic Graph
Testable components are typically simpler components.
Testability
Testability- simpler objects
- simpler interfaces
- lower number of unnecessary dependencies
- push external system interaction to the edge, isolate when possible
- remove unnecessary conditionals when possible
- promotes simpler code and more distributed, balanced set of responsibilities
- stub less, mock less, spy only when necessary
Testability
- Write a statement describing the responsibility a class or module. If there are a bunch of ANDs consider it suspicious.
- Identify “what” your object needs to fulfill that responsibility
- Identify your collaborators to meet those needs
- Identify boundaries for primary dependencies and everything else
Responsibility / Dependencies / Collaborators / Boundaries
Good statement:## The DailyCheeper is responsible for sending mobile notifications via SMS# to people have subscribed to them.#
Suspicious statement:## The DailyCheeper is responsible for sending mobile notifications via SMS# to people have subscribed to them, building reports around cheeps statistics,# subscribing users to cheeps, and updating/saving cheeps.#
Dependencies list:
- find people who are eligible and have subscribed to receiving cheeps for given time
- take into account timezones
- find out if locales/translations are necessary
- get/retrieve access to today’s cheep to send
- mobile library for sending out cheeps - access to device_id (can get off from person)
DailyCheeper
Person
Cheeps
Load Cheeps from FileSystem
Mobile Push Library
SubscriptionPrimary collaboratorsSecondary collaborators
Identify collaborators
DailyCheeper
Person
Cheeps
Load Cheeps from FileSystem
Mobile Push Library
Subscription
Unit testing scope
Identify boundaries
DailyCheeper
Person
Cheeps
Load Cheeps from FileSystem
Mobile Push Library
Subscription
Unit testing scope
Identify boundaries
- Semantic
- Appropriate for level of abstraction
- Classes, modules, methods, variables
- Avoid redundancy, ambiguity
Naming, Concepts
CustomersController#create
Customer#create
ConnectionPool#connection
MySQLAdapter#insert_sql
- Make conventions and patterns an explicit part of your vocabulary
- Make them up, or re-use useful patterns, etc you’ve found
- Evaluate, share, teach, learn
Shared Understanding / Pattern Languages
- Ruby module pattern for inheritance (for chaining behavior in a loosely coupled way, ie: ActiveRecord uses this pattern a lot when for #save)
- Constructor injection (for providing defaults but allowing object to be more easily testable)
- Boundaries (for creating a clear distinction between one part of the application and another, ie: Api, Kernel, and Border)
- Splatting/flattening conditionals (to indicate a conditional, branch of code, should not exist, investigate ways to remove it)
- Everything’s private until it’s public
- No class variables (they should be banished)
A few we use:
Ruby module pattern example
Boundaries example (API/Library)
Intuit::Api Intuit::Kernel Intuit::Border
CustomerEmployeeVendorConfiguration...
CustomerEmployeeVendorQueryDSL...
CustomerEmployeeVendorConnectionQBQL...
Barebones Intuit DefinitionsPublic API for Consumers
Mapping, additional functionality, Intuit
fixes
Boundaries example (Web App, generic)
ApplicationDelivery
Domain
Domain Services
Infrastructure
ORM
Application Services
Request comes in to find an Order
ApplicationDelivery
Domain
Domain Services
Infrastructure
ORM
Application Services
Request comes into to process batch of orders
ApplicationDelivery
Domain
Domain Services
Infrastructure
ORM
Application Services
Request comes into to process batch of orders, then notifies customer who placed order.
ApplicationDelivery
Domain
Domain Services
Infrastructure
ORM
Application Services
- Classes are great for representing entities and things which have instances (Well-Grounded Rubyist)
- Mixins are great for characteristics or properties of entities, cross-cutting concerns, explicit grouping of functionality
- Composition is a often under-used. You create a new class/object and pass in an existing one as a collaborator/dependency.
Classes, Mixins, Inheritance, and Composition
Composition
- full control over your object and API
- reduces the ripple effects of change if the API of the object you’re composing changes
- removes dependencies on parent objects you may or may not own
- simplifies testing because you own it and its dependencies
- Give yourself time to reflect
- Personal growth
- Make mid-course corrections
- Keep complexity down
- if you’re only focused on add, add, add, then you don’t give yourself time to do that
Reflection
ValuesP r a c t i c e s
over
If you actively seek ways to exploit your values, practices will
come naturally.
good bad
<insert here>
Practices change more oftenthan values.
The Vicious Stop n Go.
More effort initially.
critical point
Functionality
Com
plex
ity
May the landscape of your software be smooth rolling hills.
twitter: @zachdennis github: zdennis mutuallyhuman.com Sand Piles & Software
Articlein April PragPub