build and maintain large ruby applications ruby conf australia 2016

106
build and maintain large Ruby applications Enrico Teotti - @agenteo - http://teotti.com starting shortly

Upload: enrico-teotti

Post on 15-Apr-2017

867 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Build and maintain large ruby applications Ruby Conf Australia 2016

build and maintain large Ruby applications

Enrico Teotti - @agenteo - http://teotti.com

starting shortly

Page 2: Build and maintain large ruby applications Ruby Conf Australia 2016

build and maintain large Ruby applications

Enrico Teotti - @agenteo - http://teotti.comhttp://www.slideshare.net/agenteo

Page 3: Build and maintain large ruby applications Ruby Conf Australia 2016

http://pivotal.io/careers

Page 4: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 5: Build and maintain large ruby applications Ruby Conf Australia 2016

crowbar.rb spec.description = ”Builds and maintains large Ruby apps”

Page 6: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 7: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 8: Build and maintain large ruby applications Ruby Conf Australia 2016

–Any Java developer always ;-)

“Ruby is a toy language.”

Page 9: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

Page 10: Build and maintain large ruby applications Ruby Conf Australia 2016

http://teotti.com/cognitive-overload-in-software-development/

Page 11: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 12: Build and maintain large ruby applications Ruby Conf Australia 2016

Ruby files in a project are like ingredients in a recipe

Page 13: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 14: Build and maintain large ruby applications Ruby Conf Australia 2016

yeasthoney salt

milk flourwaterlard

sugar

arugula

squacqueroneprosciutto

Page 15: Build and maintain large ruby applications Ruby Conf Australia 2016

piadinayeasthoney salt

milk flourwaterlard

sugar

arugula

squacqueroneprosciutto

Page 16: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 17: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 18: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 19: Build and maintain large ruby applications Ruby Conf Australia 2016

3 months later

Page 20: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina

the curse of knowledge

yeasthoney salt

milk flourwaterlard

sugar

arugula

squacqueroneprosciutto

Page 21: Build and maintain large ruby applications Ruby Conf Australia 2016

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.”

Page 22: Build and maintain large ruby applications Ruby Conf Australia 2016

biscuits

mozzarella

sunflower oil

carrots

eggs

tomato puree

basil

mascarpone

coffee

cacao

yeasthoney salt

milk flourwaterlard

sugar

arugula

squacqueroneprosciutto

oregano

Page 23: Build and maintain large ruby applications Ruby Conf Australia 2016

sunflower oil

carrots

eggs

tomato puree

basil

mascarpone

coffee

cacao

yeasthoney salt

milk flourwaterlard

sugar

arugula

squacqueroneprosciutto

oregano

piadina

pizza margherita

tiramisu

carrot cake

Page 24: Build and maintain large ruby applications Ruby Conf Australia 2016

white ingredients

green ingredients

red ingredientsyellowish ingredients

orange ingredients

dark ingredients

Page 25: Build and maintain large ruby applications Ruby Conf Australia 2016

white ingredientsgreen 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/

Page 26: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina

pizza margherita

tiramisu

carrot cake

Page 27: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 28: Build and maintain large ruby applications Ruby Conf Australia 2016

namespaces

Page 29: Build and maintain large ruby applications Ruby Conf Australia 2016

# lib/blog/after_publish.rbmodule Blog class AfterPublish private def subscribe_blogger_to_promotion Promotions::Submission.new end endend

# lib/promotions/new_member.rbmodule Promotions class Submission private def fetch_member(id) # lib/membership/finder.rb Membership::Finder.new(id) end endend

promotionsblog membership

namespacescontext context

Page 30: Build and maintain large ruby applications Ruby Conf Australia 2016

promotions name finderblog membership

main Ruby application

1 year

lib

http://teotti.com/building-and-maintaing-large-ruby-on-rails-applications-for-3-years/

DB

team of 5

Page 31: Build and maintain large ruby applications Ruby Conf Australia 2016

promotions room decorator

name finderblog membershiprecipes

main Ruby application

comments

3 years

lib

DB

team of 5

Page 32: Build and maintain large ruby applications Ruby Conf Australia 2016

that’s the Ruby wayma noooooooooo

Page 33: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina worktop

tiramisu worktop

shared worktop

carrot cake worktop

pizza worktop

Page 34: Build and maintain large ruby applications Ruby Conf Australia 2016

local Ruby gems

Page 35: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 36: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 37: Build and maintain large ruby applications Ruby Conf Australia 2016

A

main Ruby application

piadina gem

Page 38: Build and maintain large ruby applications Ruby Conf Australia 2016

Apiadina gem

pizza gem

C

shared ingredients gem

B

main Ruby application

Page 39: Build and maintain large ruby applications Ruby Conf Australia 2016

Apiadina gem

pizza gem

C

shared ingredients gem

B

main Ruby application

spec.add_dependency "shared_ingredients"

# local_gems/pizza/pizza.gemspec

Page 40: Build and maintain large ruby applications Ruby Conf Australia 2016

Apiadina gem

pizza gem

C

shared ingredients gem

main Ruby application

spec.add_dependency "shared_ingredients"

# local_gems/piadina/piadina.gemspec

B

Page 41: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 42: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina gem

pizza gem

C

shared ingredients gem

B

main Ruby application

desserts gem

DA

Page 43: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 44: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina gem

pizza gem

C

shared ingredients gem

B

main Ruby application

desserts gem

DA

E

calzone gem

pizza dough gem

F

Page 45: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina gem

pizza gem

C

shared ingredients gem

B

main Ruby application

desserts gem

DA

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"

Page 46: Build and maintain large ruby applications Ruby Conf Australia 2016

piadina gem

pizza gem

shared ingredients gem

main Ruby application

desserts gem

DA

calzone gem

pizza dough gem

F

B

E

C

Page 47: Build and maintain large ruby applications Ruby Conf Australia 2016

http://teotti.com/create-dependency-structures-with-local-ruby-gems/

code & examples

Page 48: Build and maintain large ruby applications Ruby Conf Australia 2016

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

Page 49: Build and maintain large ruby applications Ruby Conf Australia 2016

!"" 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

Page 50: Build and maintain large ruby applications Ruby Conf Australia 2016

!"" 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

Page 51: Build and maintain large ruby applications Ruby Conf Australia 2016

!"" 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

http://teotti.com/gemfiles-hierarchy-in-ruby-on-rails-component-based-architecture/

Page 52: Build and maintain large ruby applications Ruby Conf Australia 2016

!"" 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.rbInitializing git repo in /Users/me/code/lab/gem-dependency-structure/local_gems/health_plan$ rm -Rf health_plan/.git*

bundle gem can create gems

main Ruby application

Page 53: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/health_plan.gemspeclib = 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 = ["[email protected]"] 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

Page 54: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/health_plan.gemspeclib = 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 = ["[email protected]"] 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

Page 55: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/spec/health_plan/aggregator_spec.rbrequire '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

Page 56: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/lib/health_plan/aggregator.rbmodule HealthPlan

class Aggregator def initialize(id) @subscriber_id = id end

def details { name: 'The full package plan'} end endend

# local_gems/health_plan/lib/health_plan.rbrequire "health_plan/version"require "health_plan/aggregator"

module HealthPlanend

gem entry point

your health plan

!"" Gemfile!"" Gemfile.lock!"" local_gems$   #"" health_plan!"" run.rb#"" spec

Page 57: Build and maintain large ruby applications Ruby Conf Australia 2016

!"" 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

Page 58: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/spec/health_plan/aggregator_spec.rbrequire '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

Page 59: Build and maintain large ruby applications Ruby Conf Australia 2016

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 = ["[email protected]"] 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

Page 60: Build and maintain large ruby applications Ruby Conf Australia 2016

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

gemspec

Page 61: Build and maintain large ruby applications Ruby Conf Australia 2016

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'

look for dependencies within the gem specification file

gemspec

Page 62: Build and maintain large ruby applications Ruby Conf Australia 2016

# local_gems/health_plan/lib/health_plan/aggregator.rbmodule 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 endend

# local_gems/health_plan/lib/health_plan.rbrequire "health_plan/version"require "health_plan/aggregator"

require "drug_information"

module HealthPlanend

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/

Page 63: Build and maintain large ruby applications Ruby Conf Australia 2016

$ bundle viz

!"" Gemfile!"" Gemfile.lock!"" local_gems$   !"" drug_information$   #"" health_plan!"" run.rb#"" spec

main Ruby application

https://github.com/shageman/cobradeps

Page 64: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

Page 65: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

unit tested

unit tested

unit testedunit tested

unit tested

acceptance tests

Page 66: Build and maintain large ruby applications Ruby Conf Australia 2016

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

Page 67: Build and maintain large ruby applications Ruby Conf Australia 2016

team diligence

Page 68: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

your health plan API

drug information

claims platform

product information

persistence DB

Page 69: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I L

modular monolith!

membership payment API

payment platform

bank transaction

credit card transaction

your health plan API

drug information

claims platform

product information

persistence DDB

Page 70: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I L

payment platform

Page 71: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 72: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I L

your health plan API

DDB

Page 73: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I L

membership payment API

DDB

Page 74: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I LDDB

Page 75: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I LDDB

Page 76: Build and maintain large ruby applications Ruby Conf Australia 2016

A

C

D

B

E

main Ruby application

F

H

I LDDB

Page 77: Build and maintain large ruby applications Ruby Conf Australia 2016

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*

DDB

Page 78: Build and maintain large ruby applications Ruby Conf Australia 2016

Director of security

Director of happiness

Director of project Death Star

Page 79: Build and maintain large ruby applications Ruby Conf Australia 2016

team diligence

Page 80: Build and maintain large ruby applications Ruby Conf Australia 2016

http://blog.codinghorror.com/the-last-responsible-moment/

team diligence

Page 81: Build and maintain large ruby applications Ruby Conf Australia 2016

http://teotti.com/rails-service-oriented-architecture-alternative-with-components/

to be continued…

premature use of SOA in a small team

Page 82: Build and maintain large ruby applications Ruby Conf Australia 2016

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

persistence DDB

Page 83: Build and maintain large ruby applications Ruby Conf Australia 2016

main Ruby application

your health plan API

drug information

claims platform

product information persistence

membership payment

APIpayment platform

bank transaction

credit card transaction

DB

Page 84: Build and maintain large ruby applications Ruby Conf Australia 2016

deploy parts of a monolith

http://teotti.com/deploy-parts-of-a-ruby-on-rails-application/

Page 85: Build and maintain large ruby applications Ruby Conf Australia 2016

monolithic Ruby application

DB

Page 86: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content

shared ui

DB

Page 87: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content ui

shared ui

DB

Persistence::ContentPieceRepository.create(params)

Page 88: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content

shared ui

DB

Page 89: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content

shared ui

DB

Page 90: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin ui

persistence

site search

componentized Ruby application

public content

shared ui

DB

Persistence::ContentPieceRepository.find_by_slug('/article-slug')

Page 91: Build and maintain large ruby applications Ruby Conf Australia 2016

deploy@adminServer $ RUNNING_MODE=admin puma

Page 92: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

Rails application

public content

shared ui

DB

Page 93: Build and maintain large ruby applications Ruby Conf Australia 2016

deploy@publicServer $ RUNNING_MODE=public puma

Page 94: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content

shared ui

DB

Page 95: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin

persistence

site search

componentized Ruby application

public content

shared ui

DB

Page 96: Build and maintain large ruby applications Ruby Conf Australia 2016

legacy migration

Page 97: Build and maintain large ruby applications Ruby Conf Australia 2016

editorial admin ui

persistence

site search

componentized Ruby application

public content ui

shared ui

DB

legacy migration

AWS SQS

massage and transform content

legacy system

pull legacy content

Page 98: Build and maintain large ruby applications Ruby Conf Australia 2016
Page 99: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

Page 100: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

team in a

fixed mindset

Page 101: Build and maintain large ruby applications Ruby Conf Australia 2016

gems require a bit of experience,gems require you to work a bit hard,

this person doesn’t write maintainable code yet,that person doesn’t understand ruby gems yet

gems require talented developersgems are only for smart developers,

this person always write unmaintainable code,that person will never understand ruby gems

https://www.youtube.com/watch?v=W47rcJowx7k

http://www.amazon.com/Mindset-The-New-Psychology-Success/dp/0345472322

Page 102: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

Page 103: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

Page 104: Build and maintain large ruby applications Ruby Conf Australia 2016

automated testing

team diligence

local Ruby gems

Page 105: Build and maintain large ruby applications Ruby Conf Australia 2016

@agenteo

Enrico Teotti

http://teotti.com

www.slideshare.net/agenteo

Page 106: Build and maintain large ruby applications Ruby Conf Australia 2016

More Links

https://leanpub.com/cbra http://teotti.com/component-based-rails-architecture-primer/ http://teotti.com/reengineer-legacy-rails-applications/