SlideShare a Scribd company logo
1 of 97
build and maintain large Ruby
applications
Enrico Teotti - @agenteo - http://teotti.com
enrico.teotti@gmail.com
starting shortly
build and maintain large Ruby
applications
Enrico Teotti - @agenteo - http://teotti.com
http://www.slideshare.net/agenteo/build-and-maintain-large-ruby-applications-ruby-conf-australia-2016
wall.rb
spec.description = ”Builds and maintains huge Ruby apps”
– Any Java developer
“Ruby is a toy language.”
automate
d testing
team
diligence
local
Ruby
gems
Booking + Driving + Billing
Booking + Driving + Billing
Booking Driving Billing
2001 2003
2007
2018
Ruby files in a project are like ingredients in a recipe
yeast
honey
salt
milk flour
water
lard
sugar
arugula
squacquerone
prosciutto
piadina
yeast
honey
salt
milk flour
water
lard
sugar
arugula
squacquerone
prosciutto
3 months later
piadina
the curse of
knowledge
yeast
honey
salt
milk flour
water
lard
sugar
arugula
squacquerone
prosciutto
6 months later
– The law of continuing change (1974) Lehman, M
“Any software system used in the real-world must change or
become less and less useful in that environment.”
– The law of increasing complexity (1974) Lehman, M
“As a program evolves, it becomes more complex, and extra
resources are needed to preserve and simplify its structure.”
biscuits
mozzarella
sunflower oil
carrots
eggs
tomato puree
basil
mascarpone
coffee
cacao
yeast
honey
salt
milk flour
water
lard
sugar
arugula
squacquerone
prosciutto
oregano
sunflower oil
carrots
gs
tomato puree
basil
mascarpone
coffee
cacao
yeast
honey
salt
milk flour
water
lard
sugar
arugula
squacquerone
prosciutto
oregano
piadina
pizza margherita
tiramisu
carrot cake
white ingredients
green ingredients
red ingredients
yellowish ingredients
orange ingredients
dark ingredients
white ingredients
green ingredients
classes grouped
by design pattern
ls -l app/
├── controllers
├── helpers
├── models
├── presenters
├── services
├── serializers
├── strategies
├── utils
└── views
http://teotti.com/application-directories-named-as-architectural-patterns-antipattern/
piadina
pizza margherita
tiramisu
carrot cake
namespaces
# lib/blog/after_publish.rb
module Blog
class AfterPublish
private
def subscribe_blogger_to_promotion
Promotions::Submission.new
end
end
end
# lib/promotions/new_member.rb
module Promotions
class Submission
private
def fetch_member(id)
# lib/membership/finder.rb
Membership::Finder.new(id)
end
end
end
promotions
blog membership
namespaces
context context
# lib/blog/after_publish.rb
module Blog
class AfterPublish
private
def subscribe_blogger_to_promotion
Promotions::Submission.new
end
end
end
# lib/promotions/new_member.rb
module Promotions
class Submission
private
def fetch_member(id)
# lib/membership/finder.rb
Membership::Finder.new(id)
end
end
end
promotions
blog membership
namespaces
context context
promotions
name
finder
blog membership
main Ruby application
1 year
lib
promotions
name
finder
blog membership
main Ruby application
1 year
lib
promotions
room
decorator
name
finder
blog membership
recipes
main Ruby application
comments
lib
3 years
promotions
room
decorator
name
finder
blog membership
recipes
main Ruby application
comments
lib
3 years
that’s the Ruby way
is that the Ruby way?
piadina worktop
tiramisu worktop
shared worktop
carrot cake worktop
pizza worktop
local Ruby gems
A
main Ruby application
piadina gem
A
piadina gem
pizza gem
C
shared
ingredients gem
main Ruby application
A
piadina gem
pizza gem
C
shared
ingredients gem
main Ruby application
spec.add_dependency "shared_ingredients"
# local_gems/pizza/pizza.gemspec
A
piadina gem
pizza gem
C
shared
ingredients gem
main Ruby application
spec.add_dependency "shared_ingredients"
# local_gems/piadina/piadina.gemspec
piadina gem
pizza gem
C
shared
ingredients gem
main Ruby application
desserts gem
D
A
piadina gem
pizza gem
C
shared
ingredients gem
main Ruby application
desserts gem
D
A
E
calzone gem
pizza dough gem
F
Conway’s Law
“organizations which design systems … are constrained to produce designs which
are copies of the communication structures of these organizations"
piadina gem
pizza gem
shared
ingredients gem
main Ruby application
desserts gem
D
A
calzone gem
pizza dough gem
F
E
C
http://teotti.com/create-dependency-structures-with-local-ruby-gems/
code & examples
A
C
D
B
E
your health plan
drug information
claims platform
product
information
membership
gem
gem
gem
gem
gem
dependency
main Ruby application
Sinatra / Rails / Hanami
http://teotti.com/create-dependency-structures-with-local-ruby-gems/
├── Gemfile
├── Gemfile.lock
├── local_gems
├── run.rb
└── spec
ruby script that
triggers entry point
gem’s behaviour
require 'health_plan'
subscriber_id = 'ASE123456789'
aggregated_drug_information = HealthPlan::Aggregator.new(subscriber_id)
puts aggregated_drug_information.details
main Ruby application
├── Gemfile
├── Gemfile.lock
├── local_gems
├── run.rb
└── spec
path 'local_gems' do
gem 'health_plan'
end
source 'https://rubygems.org'
group :test do
gem 'rspec'
end
bundler’s Gemfile
uses a path directive
to find local gems
main Ruby application
├── Gemfile
├── Gemfile.lock
├── local_gems
├── run.rb
└── spec
bundler’s Gemfile
uses a path directive
to find local gems
path 'local_gems' do
gem 'health_plan'
end
source 'https://rubygems.org'
group :test do
gem 'rspec'
end
main Ruby application
├── Gemfile
├── Gemfile.lock
├── local_gems
├── run.rb
└── spec
directory where your local gems are
$ cd local_gems
$ bundle gem health_plan
create health_plan/Gemfile
create health_plan/Rakefile
create health_plan/LICENSE.txt
create health_plan/README.md
create health_plan/.gitignore
create health_plan/health_plan.gemspec
create health_plan/lib/health_plan.rb
create health_plan/lib/health_plan/version.rb
Initializing git repo in /Users/me/code/lab/gem-dependency-structure/local_gems/health_plan
$ rm -Rf health_plan/.git*
main Ruby application
# local_gems/health_plan/health_plan.gemspec
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'health_plan/version'
Gem::Specification.new do |spec|
spec.name = "health_plan"
spec.version = HealthPlan::VERSION
spec.authors = ["Enrico Teotti"]
spec.email = ["enrico.teotti@gmail.com"]
spec.summary = %q{Write a short summary. Required.}
spec.description = %q{Write a longer description. Optional.}
spec.homepage = ""
spec.license = "MIT"
spec.files = `git ls-files -z`.split("x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
├── Gemfile
├── Gemfile.lock
├── local_gems
│ └── health_plan
├── run.rb
└── spec
spec.add_development_dependency "rspec", "3.4.0"
end
your health plan
# local_gems/health_plan/health_plan.gemspec
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'health_plan/version'
Gem::Specification.new do |spec|
spec.name = "health_plan"
spec.version = HealthPlan::VERSION
spec.authors = ["Enrico Teotti"]
spec.email = ["enrico.teotti@gmail.com"]
spec.summary = %q{Write a short summary. Required.}
spec.description = %q{Write a longer description. Optional.}
spec.homepage = ""
spec.license = "MIT"
spec.files = `git ls-files -z`.split("x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
├── Gemfile
├── Gemfile.lock
├── local_gems
│ └── health_plan
├── run.rb
└── spec
spec.add_development_dependency "rspec", "3.4.0"
end
your health plan
# local_gems/health_plan/spec/health_plan/aggregator_spec.rb
require 'spec_helper'
describe HealthPlan::Aggregator do
describe "#details" do
it "should not throw exceptions" do
aggregator = HealthPlan::Aggregator.new(12345)
expect(aggregator.details).to eq({ name: 'The full package plan'})
end
end
end
your health plan
├── Gemfile
├── Gemfile.lock
├── local_gems
│ └── health_plan
├── run.rb
└── spec
# local_gems/health_plan/lib/health_plan/aggregator.rb
module HealthPlan
class Aggregator
def initialize(id)
@subscriber_id = id
end
def details
{ name: 'The full package plan'}
end
end
end
# local_gems/health_plan/lib/health_plan.rb
require "health_plan/version"
require "health_plan/aggregator"
module HealthPlan
end
gem entry point
your health plan
├── Gemfile
├── Gemfile.lock
├── local_gems
│ └── health_plan
├── run.rb
└── spec
├── Gemfile
├── Gemfile.lock
├── local_gems
│ ├── drug_information
│ └── health_plan
├── run.rb
└── spec
your health plan
drug information
main Ruby application
$ cd local_gems
$ bundle gem drug_information
create drug_information/Gemfile
create drug_information/Rakefile
create drug_information/LICENSE.txt
create drug_information/README.md
create drug_information/.gitignore
create drug_information/drug_information.gemspec
create drug_information/lib/drug_information.rb
create drug_information/lib/drug_information/version.rb
drug information
# local_gems/health_plan/spec/health_plan/aggregator_spec.rb
require 'spec_helper'
describe HealthPlan::Aggregator do
describe "#details" do
let(:fetched_drugs) { 'something' }
before do
fetcher_double = double('DrugInformation::Fetcher', details: fetched_drugs)
allow(DrugInformation::Fetcher).to receive(:new).and_return(fetcher_double)
end
it "should not throw exceptions" do
aggregator = HealthPlan::Aggregator.new(12345)
expect(aggregator.details).to eq({ name: 'The full package plan’,
drugs: fetched_drugs })
end
end
end
your health plan
├── Gemfile
├── Gemfile.lock
├── local_gems
│ ├── drug_information
│ └── health_plan
├── run.rb
└── spec
your health plan
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'health_plan/version'
Gem::Specification.new do |spec|
spec.name = "health_plan"
spec.version = HealthPlan::VERSION
spec.authors = ["Enrico Teotti"]
spec.email = ["enrico.teotti@gmail.com"]
spec.summary = %q{Write a short summary. Required.}
spec.description = %q{Write a longer description. Optional.}
spec.homepage = ""
spec.license = "MIT"
spec.files = `git ls-files -z`.split("x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "3.4.0"
spec.add_dependency "drug_information"
end
# local_gems/health_plan/health_plan.gemspec
├── Gemfile
├── Gemfile.lock
├── local_gems
│ ├── drug_information
│ └── health_plan
├── run.rb
└── spec
your health plan
# local_gems/health_plan/Gemfile
├── Gemfile
├── Gemfile.lock
├── local_gems
│ ├── drug_information
│ └── health_plan
├── run.rb
└── spec
path '..'
source 'https://rubygems.org'
‘..’ represents the parent directory
# local_gems/health_plan/lib/health_plan/aggregator.rb
module HealthPlan
class Aggregator
def initialize(id)
@subscriber_id = id
end
def details
fetched_drug_info = DrugInformation::Fetcher.new(@subscriber_id)
{ name: 'The full package plan', drugs: fetched_drug_info.details }
end
end
end
# local_gems/health_plan/lib/health_plan.rb
require "health_plan/version"
require "health_plan/aggregator"
require "drug_information"
module HealthPlan
end
gem entry point
your health plan
├── Gemfile
├── Gemfile.lock
├── local_gems
│ ├── drug_information
│ └── health_plan
├── run.rb
└── spec
require dependent gem
http://teotti.com/create-dependency-structures-with-local-ruby-gems/
automate
d testing
A
C
D
B
E
main Ruby application
unit tested
unit tested
unit tested
unit tested
unit tested
acceptance tests
A
C
main Ruby application
B
loaded in memory, deamon or webserver
unit tested
unit tested
not unit tested
http://teotti.com/create-dependency-structures-with-local-ruby-gems#gotcha-flaky-bugs-caused-by-missing-requirement-statements
A
C
D
B
E
Jurassic Ruby application
developer
CEO
CTO
QA “resource”
QA “resource”
team
diligence
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
A
C
D
B
E
main Ruby application
F
H
I L
I find your use of
Gems disturbing
Do I really look like
a guy with a plan?
*nods then deletes
your Gem*
http://teotti.com/rails-service-oriented-architecture-alternative-with-components/
to be continued…
premature use of SOA
A
C
D
B
E
main Ruby application
F
H
I L
membership
payment API
payment
platform
bank transaction
credit card
transaction
your health plan
API
drug information
claims platform
product
information
membership
main Ruby application
your health
plan API
drug
information
claims
platform
product
information
membership
membership
payment
API
payment
platform
bank
transaction
credit card
transaction
deploy parts of a monolith
http://teotti.com/deploy-parts-of-a-ruby-on-rails-application/
monolithic Ruby application
DB
editorial admin ui
persistence
site search
componentized Ruby application
public content ui
shared ui
DB
deploy@adminServer $ RUNNING_MODE=admin puma
editorial admin ui
persistence
site search
Rails application
public content ui
shared ui
DB
deploy@publicServer $ RUNNING_MODE=public puma
http://teotti.com/deploy-parts-of-a-ruby-on-rails-application/
legacy migration
editorial admin ui
persistence
site search
Rails application
public content ui
shared ui
DB
legacy
migration
AWS
SQS
massage and
transform content
legacy system
pull legacy
content
https://medium.com/gusto-
engineering/laying-the-cultural-and-
technical-foundation-for-big-rails-
6b5ab78349ed
https://github.com/Shopify/packwerk
formerly lotus.rb
hanami.rb
automate
d testing
team
diligence
local
Ruby
gems
automate
d testing
team
diligence
local
Ruby
gems
team in a fixed
mindset
run an experiment
automate
d testing
team
diligence
local
Ruby
gems
automate
d testing
team
diligence
local
Ruby
gems
automate
d testing
team
diligence
local
Ruby
gems
Enrico Teotti - @agenteo - http://teotti.com

More Related Content

Similar to Build and maintain large Ruby applications 2023

Puppet at Bazaarvoice
Puppet at BazaarvoicePuppet at Bazaarvoice
Puppet at BazaarvoicePuppet
 
Socket applications
Socket applicationsSocket applications
Socket applicationsJoão Moura
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!cloudbring
 
Caching in a multilanguage environment
Caching in a multilanguage environmentCaching in a multilanguage environment
Caching in a multilanguage environmentelliando dias
 
Jon Arne Sæterås - Give Responsive Design a mobile performance boost
Jon Arne Sæterås - Give Responsive Design a mobile performance boost Jon Arne Sæterås - Give Responsive Design a mobile performance boost
Jon Arne Sæterås - Give Responsive Design a mobile performance boost DevConFu
 
Rails engines in large apps
Rails engines in large appsRails engines in large apps
Rails engines in large appsEnrico Teotti
 
From Ruby to Node.js
From Ruby to Node.jsFrom Ruby to Node.js
From Ruby to Node.jsjubilem
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyFabio Akita
 
TYPO3 Flow 2.0 (International PHP Conference 2013)
TYPO3 Flow 2.0 (International PHP Conference 2013)TYPO3 Flow 2.0 (International PHP Conference 2013)
TYPO3 Flow 2.0 (International PHP Conference 2013)Robert Lemke
 
Build and maintain large Ruby apps 0.0.1
Build and maintain large Ruby apps 0.0.1Build and maintain large Ruby apps 0.0.1
Build and maintain large Ruby apps 0.0.1Enrico Teotti
 
Sonar - the ring to rule them all
Sonar - the ring to rule them allSonar - the ring to rule them all
Sonar - the ring to rule them allSebastian Marek
 
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)Fabien Potencier
 
Makefiles in 2020 — Why they still matter
Makefiles in 2020 — Why they still matterMakefiles in 2020 — Why they still matter
Makefiles in 2020 — Why they still matterSimon Brüggen
 
11 page-directive
11 page-directive11 page-directive
11 page-directivesnopteck
 
atomPub, ruby y la api de 11870
atomPub, ruby y la api de 11870atomPub, ruby y la api de 11870
atomPub, ruby y la api de 11870David Calavera
 

Similar to Build and maintain large Ruby applications 2023 (20)

Puppet at Bazaarvoice
Puppet at BazaarvoicePuppet at Bazaarvoice
Puppet at Bazaarvoice
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!
 
Caching in a multilanguage environment
Caching in a multilanguage environmentCaching in a multilanguage environment
Caching in a multilanguage environment
 
Jon Arne Sæterås - Give Responsive Design a mobile performance boost
Jon Arne Sæterås - Give Responsive Design a mobile performance boost Jon Arne Sæterås - Give Responsive Design a mobile performance boost
Jon Arne Sæterås - Give Responsive Design a mobile performance boost
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
Rails engines in large apps
Rails engines in large appsRails engines in large apps
Rails engines in large apps
 
From Ruby to Node.js
From Ruby to Node.jsFrom Ruby to Node.js
From Ruby to Node.js
 
Sinatra
SinatraSinatra
Sinatra
 
Tdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema RubyTdc 2013 - Ecossistema Ruby
Tdc 2013 - Ecossistema Ruby
 
TYPO3 Flow 2.0 (International PHP Conference 2013)
TYPO3 Flow 2.0 (International PHP Conference 2013)TYPO3 Flow 2.0 (International PHP Conference 2013)
TYPO3 Flow 2.0 (International PHP Conference 2013)
 
Supa fast Ruby + Rails
Supa fast Ruby + RailsSupa fast Ruby + Rails
Supa fast Ruby + Rails
 
Build and maintain large Ruby apps 0.0.1
Build and maintain large Ruby apps 0.0.1Build and maintain large Ruby apps 0.0.1
Build and maintain large Ruby apps 0.0.1
 
Sonar - the ring to rule them all
Sonar - the ring to rule them allSonar - the ring to rule them all
Sonar - the ring to rule them all
 
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)
symfony: An Open-Source Framework for Professionals (Dutch Php Conference 2008)
 
Red5 - PHUG Workshops
Red5 - PHUG WorkshopsRed5 - PHUG Workshops
Red5 - PHUG Workshops
 
Makefiles in 2020 — Why they still matter
Makefiles in 2020 — Why they still matterMakefiles in 2020 — Why they still matter
Makefiles in 2020 — Why they still matter
 
11 page-directive
11 page-directive11 page-directive
11 page-directive
 
Create a new project in ROR
Create a new project in RORCreate a new project in ROR
Create a new project in ROR
 
atomPub, ruby y la api de 11870
atomPub, ruby y la api de 11870atomPub, ruby y la api de 11870
atomPub, ruby y la api de 11870
 

More from Enrico Teotti

Facilitating an online Agile Retrospective.pdf
Facilitating an online Agile Retrospective.pdfFacilitating an online Agile Retrospective.pdf
Facilitating an online Agile Retrospective.pdfEnrico Teotti
 
Facilitating online agile retrospectives
Facilitating online agile retrospectivesFacilitating online agile retrospectives
Facilitating online agile retrospectivesEnrico Teotti
 
Measure success in agile retrospectives
Measure success in agile retrospectivesMeasure success in agile retrospectives
Measure success in agile retrospectivesEnrico Teotti
 
3 things about public speaking
3 things about public speaking3 things about public speaking
3 things about public speakingEnrico Teotti
 
feature flagging with rails engines v0.2
feature flagging with rails engines v0.2 feature flagging with rails engines v0.2
feature flagging with rails engines v0.2 Enrico Teotti
 
Lightening a component based Rails architecture
Lightening a component based Rails architectureLightening a component based Rails architecture
Lightening a component based Rails architectureEnrico Teotti
 
Feature flagging with rails engines
Feature flagging with rails enginesFeature flagging with rails engines
Feature flagging with rails enginesEnrico Teotti
 

More from Enrico Teotti (9)

Facilitating an online Agile Retrospective.pdf
Facilitating an online Agile Retrospective.pdfFacilitating an online Agile Retrospective.pdf
Facilitating an online Agile Retrospective.pdf
 
Facilitating online agile retrospectives
Facilitating online agile retrospectivesFacilitating online agile retrospectives
Facilitating online agile retrospectives
 
Measure success in agile retrospectives
Measure success in agile retrospectivesMeasure success in agile retrospectives
Measure success in agile retrospectives
 
Structured retros
Structured retrosStructured retros
Structured retros
 
3 things about public speaking
3 things about public speaking3 things about public speaking
3 things about public speaking
 
Mindset
MindsetMindset
Mindset
 
feature flagging with rails engines v0.2
feature flagging with rails engines v0.2 feature flagging with rails engines v0.2
feature flagging with rails engines v0.2
 
Lightening a component based Rails architecture
Lightening a component based Rails architectureLightening a component based Rails architecture
Lightening a component based Rails architecture
 
Feature flagging with rails engines
Feature flagging with rails enginesFeature flagging with rails engines
Feature flagging with rails engines
 

Recently uploaded

Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 

Build and maintain large Ruby applications 2023

Editor's Notes

  1. I am not gonna come up with a gem that solves all your problems.
  2. This talk is not about performance—I am not talking about large loads
  3. I mean large business rules growing as the application development progresses— but team size always contained between 5 to 10 developers—the bulk of the logic was on the backend.
  4. That’s a joke, but devs coming from compiled languages tend to say Ruby shouldn’t be used in large projects. I don’t think that’s true but large Ruby application pose challenges
  5. that in the 10 years I worked with Ruby needed a combination of team diligence, the use of local Ruby gems and test driven development. But delivering large maintainable web applications was possible with their combination. * XXX alone was not sufficient
  6. You will have code that developers want to work on and understand on their first day rather then being overload with details. By now you might be wondering where my accent is from. I am Italian, I learned to speak english watching family guy, I lived in Australia for over 6 years and in the US for about 2 years.
  7. so my accent will be affected by those 4 regions
  8. your project ruby files deliver features like ingredients in a recipe deliver a dish
  9. imagine a kitchen worktop with the following ingredients can you tell what recipe they’re for?
  10. Those ingredients are for piadina a popular italian street snack priced around 5 AUD
  11. But in Sydney Australia it can only be found in one cafe opened by two young Italians near Bondi Beach for 17 Dollars!. A simple recipe can be very profitable. This story is inspired by real facts so I am gonna make up some names… I am gonna call the owners… Mario and Luigi.
  12. Mario and Luigi are from Brescia, a province where piadina isn’t exceptionally good but they are the first and only place selling piadina in Sydney so when me and my Italian friends wanted to have it we had to go there, and at first it was pretty busy.
  13. Whenever we went there I never saw Mario and Luigi making piadinas, they had two ozzie students with no cooking experience named… Stevo and Anna. Stevo and Anna, familiarised themselves with the ingredients, learned the recipe and started making the profitable piadinas for Mario and Luigi.
  14. Everything is going well until 3 months later Anna goes on a gap year and Mario has to hire someone new: Diego, a new student also with no cooking experience.
  15. Diego doesn’t really know what’s going on Mario, Luigi laugh at how slow he is in picking up the recipe but Stevo helps Diego overcome the intrinsic load of learning the recipe and the ingredients and everything is back to normal.
  16. Piadina was selling just ok so to be more competitive Mario and Luigi decide to add more recipes to the menu: pizza, tiramisu and carrot cake
  17. Can you find the ingredients for the new recipes? We probably find one ingredient for carrot cake… but we might struggle to find the rest. Can you still find piadina’s ingredients? Stevo's reaction was a mix of confusion and frustration. On top of the intrinsic difficulty of learning new recipes, there is an extraneous (ecstrinius) load of finding the ingredients on the messy kitchen worktop.
  18. To Mario and Luigi’s eyes there are obviously four recipes now. To Stevo’s it just takes longer to find the ingredients and prepare the dishes. Stevo is affected by cognitive overload. He feels like he’s over his depth, is it because he’s not smart enough? Or maybe the worktop is too disorganised? He’s a novice and unsure about his skills on how to proceed so he ask Mario and Luigi to organise these ingredients.
  19. Stevo come in the following day and ingredients on the worktop are actually labelled by colour this is making it very difficult to recognise a recipe ingredients some of you might have noticed the ingredients were grouped by color from the first slide, did they bother you then? So when cooking pizza Stevo needs to think, which ingredients are white? which are red? which are green? When he complains Mario replies: that’s the convention in Italy! Have you ever seen this happening in a Ruby application?
  20. are ok in a tiny app but in a large app it’s harder to navigate large codebases describes an attribute of that class but it says nothing at all about its operational context you might be using single responsibility and good object oriented patterns but how does that help in finding boundaries in your application? [pause ..]
  21. Stevo suggests dedicated areas of the worktop to each recipe? This allows Stevo to get the ingredients required to work on a specific dish, there are shared ingredients but it’s easy enough to recognise them and it doesn’t create too much overhead. He can look at Diego next to him focusing on preparing pizza. But then one day Stevo is rushing preparing a carrot cake, he wants to leave the kitchen and go play beach volleyball down in Bondi. He reaches and grab the milk jar but it slips off his big hands and cracks on the worktop, milk leaking everywhere spoiling the tiramisu cream and the raising pizza dough sitting next to it.
  22. this is similar to Ruby namespaces, they provide a simple form of separation in a Ruby application
  23. it’s a first step in the right direction, it ensures your application has some boundaries a group of classes defined within a namespace becomes specific to that context and force external clients to use the full namespace to access them [explain code] There are dependencies but you won’t be able to tell unless you look and familiarise yourself with the source code.
  24. it’s a first step in the right direction, it ensures your application has some boundaries a group of classes defined within a namespace becomes specific to that context and force external clients to use the full namespace to access them [explain code] There are dependencies but you won’t be able to tell unless you look and familiarise yourself with the source code.
  25. In a Rails project ongoing for 3 years (team of 5) we used namespaces to keep separation between vertical slices of the application’s functionality but when the project was about one year old we had a tangle of cross namespaces dependencies hard to follow and slowing down development.
  26. In a Rails project ongoing for 3 years (team of 5) we used namespaces to keep separation between vertical slices of the application’s functionality but when the project was about one year old we had a tangle of cross namespaces dependencies hard to follow and slowing down development.
  27. Some laughed when we were concerned about the tangling dependencies. Onboarding new developers was a long task causing them cognitive overload. The vertical boundaries were leaking and out of control. Simple changes in the middle of the tangle would take a long time and constantly introduce unpredicted side effects that tests were unable to catch. There was a desire to fix the problem but we couldn’t commit to team wide diligent work. In the end it became the app nobody wanted to touch. For many that’s just how Ruby is. I disagree.
  28. Some laughed when we were concerned about the tangling dependencies. Onboarding new developers was a long task causing them cognitive overload. The vertical boundaries were leaking and out of control. Simple changes in the middle of the tangle would take a long time and constantly introduce unpredicted side effects that tests were unable to catch. There was a desire to fix the problem but we couldn’t commit to team wide diligent work. In the end it became the app nobody wanted to touch. For many that’s just how Ruby is. I disagree.
  29. To prevent more incidents Mario, Luigi Stevo and Diego agree to have separate worktops for each recipe… and a shared worktop. If there is a leak it will be contained on that recipe kitchen worktop. We can now assign a cook to a specific recipe.
  30. this is similar to using local Ruby gems
  31. everyone is probably familiar with open source Ruby gems distributed over the internet and there is a misconception that is all gems can do. I don’t want to make my business logic open source! Fair point.
  32. gems don’t need to be published. They can live within the application repository, used as building blocks creating solid and distinct boundaries. An intention revealing dependency structure that helps navigating and changing code. the separation isn’t as solid as with different worktops because when a Ruby application requires your first entry point gem it’ll require all its dependencies so all the classes will be in memory we’ll see how you can ensure the dependency structure is solid by unit testing the local gem
  33. At the beginning there is just one gem. The structure will evolve over weeks and months as more responsibilities piled up.
  34. Each gem has a specification file that indicate its local dependencies. That’s your application map, that’s how you reduce cognitive load.
  35. The objective is an intention revealing dependency structure that reduce the developers cognitive load and facilitate conversations with business owners. The risk is to split in too fine grained components creating a dependency structure that is purely technical and doesn’t represent any business rule impeding conversations with business owners. [pause ..] My guideline is to map business operational areas to objects names and gems. When more then two or three concepts are living in the same gem I ask the business owner if they think it’s a different context, perhaps a different team or company operating at the other end of this feature?
  36. The objective is an intention revealing dependency structure that reduce the developers cognitive load and facilitate conversations with business owners and within the team. The risk is to split in too fine grained components creating a dependency structure that is purely technical and doesn’t represent any business rule impeding conversations with business owners. Without product owners a team can self determine those boundaries. [pause ..] My guideline is to map business operational areas to objects names and gems. When more then two or three concepts are living in the same gem I ask the business owner if they think it’s a different context, perhaps a different team or company operating at the other end of this feature? Conway’s law help with this. It’s hard work and expect the boundaries to change, the gem might be renamed stuff moved or added as the application evolves. And that’s where the term evolutionary design comes from. A local gems dependency structure is complementary to good object oriented programming. You should still use your favourite flavour of patterns.
  37. The objective is an intention revealing dependency structure that reduce the developers cognitive load and facilitate conversations with business owners and within the team. The risk is to split in too fine grained components creating a dependency structure that is purely technical and doesn’t represent any business rule impeding conversations with business owners. Without product owners a team can self determine those boundaries. [pause ..] My guideline is to map business operational areas to objects names and gems. When more then two or three concepts are living in the same gem I ask the business owner if they think it’s a different context, perhaps a different team or company operating at the other end of this feature? Conway’s law help with this. It’s hard work and expect the boundaries to change, the gem might be renamed stuff moved or added as the application evolves. And that’s where the term evolutionary design comes from. A local gems dependency structure is complementary to good object oriented programming. You should still use your favourite flavour of patterns.
  38. For the next five minutes we’ll be diving in technical details of setting up a local gem dependency structure to ensure you get a first pass the example is explained in detail on my blogpost and code is on github , if I loose you come to me after the talk and I’ll try to clarify, after the next 5 we’ll go back to the same high level with real usages of local gems
  39. You can use local Ruby gems with any framework. The framework is used as a a delivery mechanism triggering calls to your business logic encapsulated within gems This is gonna be a skeleton example focused on connecting two classes living in two separate local gems. In reality each gem has multiple classes with one responsibility helping that one class doing its job.
  40. A simple script triggers our entry point gem aggregator class.
  41. create gem in a directory meaningful to your team bundle provides a gem option to create gems delete gem repository
  42. * lock to a specific version to prevent multiple local gems to install different versions of spec
  43. This is a simplified example focusing on connecting the local gems. Within drug_information you’d have a 5/6 classes with one responsibility each helping fetcher to do its job.
  44. unit tests exercising each gem’s responsibility and a high level acceptance test ensuring integrations worked if somebody change product information code to access membership breaking the dependency structure only the automated test will warn us about that
  45. flaky bugs can spawn depending on gem requirement order When your application first access B, and B doesn’t require C but uses its code a run time error will be triggered. And this is why you must use automated tests to adopt this strategy.
  46. unit tests exercising each gem’s responsibility and a high level acceptance test ensuring integrations worked if there is a in breaking the dependency structure only the automated test will warn us about that
  47. giving the team an opportunity to talk about the boundaries. At runtime, since usually all the gems are loaded in memory you’re unlikely to see any problem.
  48. say you have an A and F team, You can even assign teams to a boundary.
  49. You can even assign teams to a boundary.
  50. The whole team is responsible for the shared behaviour, that’s why diligence is important. This should be totally achievable for teams up to ~10/12
  51. team diligence should be achievable in a team of 6/10 people… perhaps you can convince skeptics to run an experiment? See how they feel?
  52. as the team and the company grows it will be harder to ensure in process boundaries, that’s when the modular monolith is ready to be broken up in to services to introduce an explicit boundary perhaps moving parts of the modular monolith in to services is the natural evolution for your project. And the modular monolith is ready to be sliced!
  53. How would it look with just using namespaces? *** try switch from gem boundaries to recipe
  54. without a dependency structure you’ve lost visibility of how those namespaces relate to each other and affected by cognitive overload that’s the monolith you want to avoid
  55. This strategy allowed us to deploy parts of a Rails application.
  56. This strategy allowed us to deploy parts of a monolithic app. 3 months in to development we were told half the app had to be deployed to a separate server. Some manager was pushing for services, an API used by the two contexts of the application.
  57. The two entry points had a shared local gems dependency structure.
  58. we uses an env variable on the admin server to tell Ruby what functionality to load. That functionality was encapsulated in an entry point gem.
  59. Thanks for listening, reach out if you have any question.
  60. Hanami is a 2 years old web framework that brings a solid modular approach to the Ruby ecosystem. Container applications are core to the framework as well as a better separation between the delivery mechanism and the persistence layer (entities and respositories). But when complex business logic is not encapsulated you will end up with the usual tangle of cross namespace dependencies littering the lib folder.
  61. Your code might be simply making piadina today but how likely is it to stay that way? You can keep piling files on one kitchen worktop or start thinking in terms of separate worktops for separate contexts.
  62. A team in a fixed mindset won’t even try and this strategy results will be very limited. A team in a fixed mindset believes skills and abilities are set… you either have it or your don’t… and failure means you don’t. A team in a fixed mindset believes they are not talented enough to use gems Or the opposite, they’re too smart to use local gems… a hack… not the Ruby way… — So rather then taking on new challenges—like local Ruby gems—this team sticks to what they know well… that way they can be safe, keep looking smart.
  63. speak with your team about local gems encapsulating your application boundaries, ensure they are on board
  64. run an experiment on a section of your code, measure the results: bugs and velocity between the modularised section of your app and the rest to convince skeptical with empirical data.
  65. And don't forget to TDD your gems to ensure their dependency structure is solid I believe it will help you as it helped me build and maintain large Ruby applications.
  66. Thanks for listening, reach out if you have any question.