SlideShare ist ein Scribd-Unternehmen logo
1 von 178
Downloaden Sie, um offline zu lesen
SAY GOODBYE TO
PROCEDURAL*
PROGRAMMING
ANOTHER USELESS PRESENTATION
BROUGHT TO YOU BY @APOTONICK
SAY GOODBYE TO
PROCEDURAL*
PROGRAMMING
* AS WE KNOW IT.
<wrong>
REVEAL.JS
AND HOW TO MASTER IT, PART I OF VIII
[ ] DIAGRAMS
[ ] 6 MEMES
[ ] 2 BULLET POINT LISTS
[ ] QUOTE FROM SOMEONE
[ ] MORE DIAGRAMS
[ ] TRUCKLOADS OF CODE (you wanted it)
[ ] DIAGRAMS
[ ] 6 MEMES
[x ] 2 BULLET POINT LISTS
[ ] QUOTE FROM SOMEONE
[ ] MORE DIAGRAMS
[ ] TRUCKLOADS OF CODE (you wanted it)
class Post < ActiveRecord::Base
validates :body, presence:true
validates :author, presence:true
after_save :notify_moderators!, if: :create?
end
 
class PostsController < ApplicationController
def create
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
if post.update_attributes(
params.require(:post).permit(:title)
)
post.save
notify_current_user!
else
render :new
end
end
end
Let's not talk
about persistence!
Let's not talk
about business logic!
Let's not talk
about views!
I SAID: RAILS VIEWS!
Notes:
let's come back to the problems in our example it's
hard to understand what we are trying to do and:
HOW DO I
TEST THAT?
class Post < ActiveRecord::Base
validates :body, presence:true
validates :author, presence:true
after_save :notify_moderators!, if: :create?
end
describe Post do
it "validates and notifies moderators" do
post = Post.create( valid_params )
expect(post).to be_persisted
end
end
class Post < ActiveRecord::Base
validates :body, presence:true
validates :author, presence:true
after_save :notify_moderators!, if: :create?
end
describe Post do
it "validates and notifies moderators" do
post = Post.create( valid_params )
expect(post).to be_persisted
end
end
it do
controller = Controller.new
controller.create( valid_params )
expect(Post.last).to be_persisted
end
describe BlogPostsController do
it "creates BlogPost model" do
post :create, blog_post: valid_params
expect(response).to be_ok
expect(BlogPost.last).to be_persisted
end
end
...THINKING...
...THINKING...
[...] It extends the basic MVC pattern
with new abstractions.
NO!
class MyService
def self.call(args)
# do something here
end
end
MyService.( valid_params )
Notes: we don't need any domain logic, that's very
user specific and shouldn't be dictated by "my
framework"
class MyService
def call(params)
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
post.update_attributes(
params.require(:post).permit(:title)
)
if post.save
notify_current_user!
end
end
end
[ ] DIAGRAMS
[x] 6 MEMES
[x ] 2 BULLET POINT LISTS
[ ] QUOTE FROM SOMEONE
[ ] MORE DIAGRAMS
[ ] TRUCKLOADS OF CODE (you wanted it)
class MyService
def call(params)
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
post.update_attributes(
params.require(:post).permit(:title)
)
if post.save
notify_current_user!
end
end
end
TEST
it do
service = MyService.new
service.call( valid_params )
expect(Post.last).to be_persisted
end
HAPPY!
...THINKING...
SERVICE OBJECTS, REVISITED
[x] Encapsulation
[x] Testing
[ ] What to return?
[ ] Validations extracted?
[ ] Extendable
class MyService
def call(params)
end
end
Is the problem the
procedural* code design?
AND THAT'S TRB.
THANK YOU!
QUESTIONS?
OK, I GOT
A QUESTION
THEN:
DO YOU WANT
SOME CODE?
DO YOU WANT
SOME CODE?
NO?
class Create < Trailblazer::Operation
#
#
#
end
class BlogPost::Create < Trailblazer::Operation
#
#
#
end
class Create < Trailblazer::Operation
#
#
#
end
class Create < Trailblazer::Operation
def process(params)
# sam's code here
end
end
Notes: not really extendable
class Create < Trailblazer::Operation
def process(params)
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
post.update_attributes(
params.require(:post).permit(:title)
)
if post.save
notify_current_user!
end
end
end
class Create < Trailblazer::Operation
#
#
#
end
result = Create.()
result.success? #=> true
Notes:
Hooray, we have an API for service objects!
HOORAY, A
SERVICE
OBJECT
API!
class Create < Trailblazer::Operation
#
#
#
#
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify_current_user!
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify_current_user!
end
class Create < Trailblazer::Operation
step :create_model!
#
#
#
#
end
class Create < Trailblazer::Operation
step :create_model!
def create_model!(options, **)
end
end
CREATE MODEL
class Create < Trailblazer::Operation
step :create_model!
def create_model!(options, **)
options["model"] = BlogPost.new
end
end
result = Create.()
result.success? #=> true
result["model"] #=> #<BlogPost id:nil, ..>
VALIDATE
class Create < Trailblazer::Operation
step :create_model!
step :validate!
def create_model!(options, **)
# ..
def validate!(options, params:, **)
# validate params
end
end
valid_params = { body: "Blogging's fun. #not" }
Create.( valid_params )
class Create < Trailblazer::Operation
# ..
def validate!(options, params:, **)
params #=> { body: "Blogging's fun. #not" }
end
end
Notes: sending params into the op
class Create < Trailblazer::Operation
# ..
def validate!(options, params:, **)
model = options["model"] # from the create_model! step...
if model.update_attributes(params)
true
else
false
end
end
end
class Create < Trailblazer::Operation
# ..
def validate!(options, params:, model:, **)
#
#
if model.update_attributes(params)
true
else
false
end
end
end
#class Create < Trailblazer::Operation
# ..
def validate!(options, params:, model:, **)
if model.update_attributes(params)
true
else
false
end
end
#end
#class Create < Trailblazer::Operation
# ..
def validate!(options, params:, model:, **)
#
#
#
#
model.update_attributes(params)
end
#end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
#
#
#
#
#
#
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
#def create_model!(options, **)
#def validate!(options, params:, **)
def save!(options, params:, model:, **)
true
end
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
#def create_model!(options, **)
#def validate!(options, params:, **)
#def save!(options, params:, model:, **)
def notify!(options, model:, **)
MyMailer.call(model)
end
end
HAPPY
TIMES!
... AND WHEN
THINGS
GO WRONG?
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
#def create_model!(options, **)
#def validate!(options, params:, **)
#def save!(options, params:, model:, **)
#def notify!(options, model:, **)
end
class Create < Trailblazer::Operation
step :create_model!
step :validate! [XXX]
step :save!
step :notify!
#def create_model!(options, **)
#def validate!(options, params:, **)
#def save!(options, params:, model:, **)
#def notify!(options, model:, **)
end
#class Create < Trailblazer::Operation
# ..
def validate!(options, params:, model:, **)
model.update_attributes(params) #=> false
end
#end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
failure :handle!
#..
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
failure :handle!
#..
def handle!(options, **)
options["error"] = "don't cry!"
end
end
result = Create.( { title: nil } )
result.success? #=> false
result["error"] = "don't cry!"
RAILWAYS
ROCK!
BUT ISN'T THAT
SUPER
COMPLEX?
DUDE.
Notes: do you find this more complex than this?
class MyService
def call(params)
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
if post.update_attributes(
params.require(:post).permit(:title)
)
unless notify_current_user!
if ...
else
end
end
end
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
failure :handle!
# ..
end
def create_model!(options, **)
def validate!( options, params:, **)
def save!( options, params:, model:, **)
def notify!( options, model:, **)
result = Create.( { title: nil } )
result.success? #=> false
result["error"] #=> "don't cry!"
result["model"] #=> #<BlogPost title: nil>
TEST
it "fails with empty title" do
result = Create.( { title: nil } )
expect(result).to be_success
expect(result["error"]).to eq("don't cry!")
expect(result["model"]).to be_persisted
end
rspec-trailblazer
minitest-trailblazer
Notes:
validations still in model
class PostsController < ApplicationController
def create
return unless can?(current_user, Post, :new)
post = Post.new(author: current_user)
if post.update_attributes(
params.require(:post).permit(:title))
notify_current_user!
else
render :new
end
end
end
class PostsController < ApplicationController
def create
return unless can?(current_user, Post, :new)
#
#
#
result = BlogPost::Create.( params )
if result.failure?
render :new
end
end
end
AUTHORIZATION
def create
return unless can?(current_user, Post, :new)
# ..
class Create < Trailblazer::Operation
step :authorize!
#step :create_model!
#step :validate!
#step :save!
#step :notify!
#failure :handle!
# ..
end
class Create < Trailblazer::Operation
step :authorize!
# ..
def authorize!(options, current_user:, **)
CouldCould.can?(current_user, Post, :new)
end
end
CURRENT WHAT?
def authorize!(options, current_user:, **)
CouldCould.can?(
current_user, # wtf?
Post, :new
)
end
class PostsController < ApplicationController
def create
return unless can?(current_user, Post, :new)
result = BlogPost::Create.( params )
#
#
#
if result.failure?
render :new
end
end
end
class PostsController < ApplicationController
def create
return unless can?(current_user, Post, :new)
result = BlogPost::Create.(
params,
"current_user" => current_user
)
if result.failure?
render :new
end
end
end
class PostsController < ApplicationController
def create
#return unless can?(current_user, Post, :new)
#
result = BlogPost::Create.(
params,
"current_user" => current_user
)
if result.failure?
render :new
end
end
end
class PostsController < ApplicationController
def create
result = BlogPost::Create.(
params,
"current_user" => current_user
)
if result.failure?
render :new
end
end
end
class PostsController < ApplicationController
def create
run BlogPost::Create, "current_user" => current_user do
return
end
render :new
end
end
class PostsController < ApplicationController
def create
run BlogPost::Create do
return
end
render :new
end
end
class PostsController < ApplicationController
def create
run BlogPost::Create do |result|
return redirect_to blog_post_path(result["model"].id)
end
render :new
end
end
class PostsController < ApplicationController
def create
run BlogPost::Create do |result|
return redirect_to blog_post_path(result["model"
end
render :new
end
end
DEPENDENCY INJECTION
it "works with current_user" do
result = Create.(
valid_params,
"current_user" => User.find(1) )
# ..
end
class Create < Trailblazer::Operation
step :authorize!
# ..
def authorize!(options, current_user:, **)
CouldCould.can?(current_user, Post, :new)
end
end
class Create < Trailblazer::Operation
step MyAuth
# ..
class MyAuth
def self.call(options, current_user:, **)
CouldCould.can?(current_user, Post, :new)
end
end
end
class Create < Trailblazer::Operation
step MyAuthCallableSittingSomewhere
# ..
#class MyAuth
# def self.call(options, current_user:, **)
# CouldCould.can?(current_user, Post, :new)
# end
#end
end
DYI SUCKS
class Create < Trailblazer::Operation
step Policy::CanCan( Post, :new )
# step :model!
# ..
end
VALIDATIONS:
A STORY OF MANKIND
class Post < ActiveRecord::Base
validates :title, presence:true
validates :body, presence:true
#after_save :notify_moderators!, if: :create?
end
module BlogPost
module Contract
class Create::Create < Reform::Form
property :title
property :body
validates :title, presence:true
validates :body, presence:true
end
end
end
class Create < Trailblazer::Operation
step Policy::CanCan( Post, :new )
step :model!
step :validate!
step :notify!
# ..
def model!(options, **)
def validate!(options, **)
# ..
end
class Create < Trailblazer::Operation
step Policy::CanCan( Post, :new )
step :model!
step Contract::Build( constant: Contract::Create )
step Contract::Validate()
step Contract::Persist()
step :notify!
# ..
def model!(options, **)
# ..
end
BPMN
class Create < Trailblazer::Operation
step :create_model!
step :validate!
step :save!
step :notify!
failure :handle!
# ..
end
result = Create.(
params,
"current_user" => ..
)
SAY GOODBYE TO
PROCEDURAL*
PROGRAMMING
* AS WE KNOW IT.
Trailblazer is awesome!
             -- Someone
[ ] DIAGRAMS
[x] 6 MEMES
[xX] 2 BULLET POINT LISTS
[x] QUOTE FROM SOMEONE
[x] MORE DIAGRAMS
[ ] TRUCKLOADS OF CODE (you wanted it)
@APOTONICK
❤

Weitere ähnliche Inhalte

Was ist angesagt?

10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 

Was ist angesagt? (20)

Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native Side
 
Synapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephp
 
Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-Programming
 
Two Scoops of Django - Common Patterns for Forms
Two Scoops of Django - Common Patterns for FormsTwo Scoops of Django - Common Patterns for Forms
Two Scoops of Django - Common Patterns for Forms
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Ember - introduction
Ember - introductionEmber - introduction
Ember - introduction
 
Solid angular
Solid angularSolid angular
Solid angular
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Complex Architectures in Ember
Complex Architectures in EmberComplex Architectures in Ember
Complex Architectures in Ember
 
Sylius and Api Platform The story of integration
Sylius and Api Platform The story of integrationSylius and Api Platform The story of integration
Sylius and Api Platform The story of integration
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
 
Vuejs testing
Vuejs testingVuejs testing
Vuejs testing
 
Introduction To Angular's reactive forms
Introduction To Angular's reactive formsIntroduction To Angular's reactive forms
Introduction To Angular's reactive forms
 
Cucumber
CucumberCucumber
Cucumber
 
MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8
MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8
MidCamp 2016 - Demystifying AJAX Callback Commands in Drupal 8
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
 

Andere mochten auch

Andere mochten auch (12)

Collage days
Collage daysCollage days
Collage days
 
Rodauth: Clean Authentication - Valentine Ostakh
Rodauth: Clean Authentication - Valentine OstakhRodauth: Clean Authentication - Valentine Ostakh
Rodauth: Clean Authentication - Valentine Ostakh
 
Ruby Gems and Native Extensions - Stas Volovyk
Ruby Gems and Native Extensions - Stas VolovykRuby Gems and Native Extensions - Stas Volovyk
Ruby Gems and Native Extensions - Stas Volovyk
 
Funtional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail BortnykFuntional Ruby - Mikhail Bortnyk
Funtional Ruby - Mikhail Bortnyk
 
Evident Secrets of Successful Application - Max Goncharov
Evident Secrets of Successful Application - Max GoncharovEvident Secrets of Successful Application - Max Goncharov
Evident Secrets of Successful Application - Max Goncharov
 
Functional Web Apps with WebMachine Framework - Mikhail Bortnyk
Functional Web Apps with WebMachine Framework - Mikhail BortnykFunctional Web Apps with WebMachine Framework - Mikhail Bortnyk
Functional Web Apps with WebMachine Framework - Mikhail Bortnyk
 
Lets build a game (in 24 min) by Ivan Zarea
Lets build a game (in 24 min) by Ivan ZareaLets build a game (in 24 min) by Ivan Zarea
Lets build a game (in 24 min) by Ivan Zarea
 
A Farewell Letter_ Gabriel Garcia Marquez
A Farewell Letter_ Gabriel Garcia MarquezA Farewell Letter_ Gabriel Garcia Marquez
A Farewell Letter_ Gabriel Garcia Marquez
 
Farewell quiz
Farewell quizFarewell quiz
Farewell quiz
 
Funny retirement slides
Funny retirement slidesFunny retirement slides
Funny retirement slides
 
Farewell powerpoint 2
Farewell powerpoint 2Farewell powerpoint 2
Farewell powerpoint 2
 
FAREWELL
FAREWELLFAREWELL
FAREWELL
 

Ähnlich wie Say Goodbye to Procedural Programming - Nick Sutterer

Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
Decent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivarsDecent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivars
Leonardo Soto
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
Ran Mizrahi
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
Avinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPressAvinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPress
wpnepal
 

Ähnlich wie Say Goodbye to Procedural Programming - Nick Sutterer (20)

Where's My SQL? Designing Databases with ActiveRecord Migrations
Where's My SQL? Designing Databases with ActiveRecord MigrationsWhere's My SQL? Designing Databases with ActiveRecord Migrations
Where's My SQL? Designing Databases with ActiveRecord Migrations
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Why ruby
Why rubyWhy ruby
Why ruby
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron Patterson
 
Decent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivarsDecent exposure: Controladores sin @ivars
Decent exposure: Controladores sin @ivars
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
Django quickstart
Django quickstartDjango quickstart
Django quickstart
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Avinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPressAvinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPress
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
QConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebQConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações Web
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 

Mehr von Ruby Meditation

Mehr von Ruby Meditation (20)

Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30Is this Legacy or Revenant Code? - Sergey Sergyenko  | Ruby Meditation 30
Is this Legacy or Revenant Code? - Sergey Sergyenko | Ruby Meditation 30
 
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
Life with GraphQL API: good practices and unresolved issues - Roman Dubrovsky...
 
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
Where is your license, dude? - Viacheslav Miroshnychenko | Ruby Meditation 29
 
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
Dry-validation update. Dry-validation vs Dry-schema 1.0 - Aleksandra Stolyar ...
 
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28 How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
How to cook Rabbit on Production - Bohdan Parshentsev | Ruby Meditation 28
 
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
How to cook Rabbit on Production - Serhiy Nazarov | Ruby Meditation 28
 
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
Reinventing the wheel - why do it and how to feel good about it - Julik Tarkh...
 
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
Performance Optimization 101 for Ruby developers - Nihad Abbasov (ENG) | Ruby...
 
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
Use cases for Serverless Technologies - Ruslan Tolstov (RUS) | Ruby Meditatio...
 
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
 
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
What/How to do with GraphQL? - Valentyn Ostakh (ENG) | Ruby Meditation 27
 
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26New features in Rails 6 -  Nihad Abbasov (RUS) | Ruby Meditation 26
New features in Rails 6 - Nihad Abbasov (RUS) | Ruby Meditation 26
 
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
Security Scanning Overview - Tetiana Chupryna (RUS) | Ruby Meditation 26
 
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
Teach your application eloquence. Logs, metrics, traces - Dmytro Shapovalov (...
 
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
Best practices. Exploring - Ike Kurghinyan (RUS) | Ruby Meditation 26
 
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
Road to A/B testing - Alexey Vasiliev (ENG) | Ruby Meditation 25
 
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
Concurrency in production. Real life example - Dmytro Herasymuk | Ruby Medita...
 
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
Data encryption for Ruby web applications - Dmytro Shapovalov (RUS) | Ruby Me...
 
Rails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan GusievRails App performance at the limit - Bogdan Gusiev
Rails App performance at the limit - Bogdan Gusiev
 
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
GDPR. Next Y2K in 2018? - Anton Tkachov | Ruby Meditation #23
 

Kürzlich hochgeladen

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Kürzlich hochgeladen (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 

Say Goodbye to Procedural Programming - Nick Sutterer

  • 1. SAY GOODBYE TO PROCEDURAL* PROGRAMMING ANOTHER USELESS PRESENTATION BROUGHT TO YOU BY @APOTONICK
  • 3.
  • 5. REVEAL.JS AND HOW TO MASTER IT, PART I OF VIII
  • 6. [ ] DIAGRAMS [ ] 6 MEMES [ ] 2 BULLET POINT LISTS [ ] QUOTE FROM SOMEONE [ ] MORE DIAGRAMS [ ] TRUCKLOADS OF CODE (you wanted it)
  • 7. [ ] DIAGRAMS [ ] 6 MEMES [x ] 2 BULLET POINT LISTS [ ] QUOTE FROM SOMEONE [ ] MORE DIAGRAMS [ ] TRUCKLOADS OF CODE (you wanted it)
  • 8.
  • 9.
  • 10.
  • 11.
  • 12. class Post < ActiveRecord::Base validates :body, presence:true validates :author, presence:true after_save :notify_moderators!, if: :create? end
  • 13.   class PostsController < ApplicationController def create return unless can?(current_user, Post, :new) post = Post.new(author: current_user) if post.update_attributes( params.require(:post).permit(:title) ) post.save notify_current_user! else render :new end end end
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24. Let's not talk about persistence! Let's not talk about business logic! Let's not talk about views!
  • 25.
  • 26. I SAID: RAILS VIEWS!
  • 27.
  • 28.
  • 29. Notes: let's come back to the problems in our example it's hard to understand what we are trying to do and:
  • 30. HOW DO I TEST THAT?
  • 31. class Post < ActiveRecord::Base validates :body, presence:true validates :author, presence:true after_save :notify_moderators!, if: :create? end describe Post do it "validates and notifies moderators" do post = Post.create( valid_params ) expect(post).to be_persisted end end
  • 32. class Post < ActiveRecord::Base validates :body, presence:true validates :author, presence:true after_save :notify_moderators!, if: :create? end describe Post do it "validates and notifies moderators" do post = Post.create( valid_params ) expect(post).to be_persisted end end
  • 33. it do controller = Controller.new controller.create( valid_params ) expect(Post.last).to be_persisted end
  • 34.
  • 35. describe BlogPostsController do it "creates BlogPost model" do post :create, blog_post: valid_params expect(response).to be_ok expect(BlogPost.last).to be_persisted end end
  • 36.
  • 39.
  • 40.
  • 41.
  • 42. [...] It extends the basic MVC pattern with new abstractions.
  • 43. NO!
  • 44.
  • 45.
  • 46.
  • 47.
  • 48. class MyService def self.call(args) # do something here end end MyService.( valid_params )
  • 49. Notes: we don't need any domain logic, that's very user specific and shouldn't be dictated by "my framework"
  • 50. class MyService def call(params) return unless can?(current_user, Post, :new) post = Post.new(author: current_user) post.update_attributes( params.require(:post).permit(:title) ) if post.save notify_current_user! end end end
  • 51.
  • 52. [ ] DIAGRAMS [x] 6 MEMES [x ] 2 BULLET POINT LISTS [ ] QUOTE FROM SOMEONE [ ] MORE DIAGRAMS [ ] TRUCKLOADS OF CODE (you wanted it)
  • 53. class MyService def call(params) return unless can?(current_user, Post, :new) post = Post.new(author: current_user) post.update_attributes( params.require(:post).permit(:title) ) if post.save notify_current_user! end end end
  • 54. TEST it do service = MyService.new service.call( valid_params ) expect(Post.last).to be_persisted end
  • 57. SERVICE OBJECTS, REVISITED [x] Encapsulation [x] Testing [ ] What to return? [ ] Validations extracted? [ ] Extendable class MyService def call(params) end end
  • 58. Is the problem the procedural* code design?
  • 59.
  • 60.
  • 61.
  • 62.
  • 65. OK, I GOT A QUESTION THEN:
  • 68. NO?
  • 69. class Create < Trailblazer::Operation # # # end
  • 70. class BlogPost::Create < Trailblazer::Operation # # # end
  • 71. class Create < Trailblazer::Operation # # # end
  • 72. class Create < Trailblazer::Operation def process(params) # sam's code here end end
  • 73. Notes: not really extendable
  • 74. class Create < Trailblazer::Operation def process(params) return unless can?(current_user, Post, :new) post = Post.new(author: current_user) post.update_attributes( params.require(:post).permit(:title) ) if post.save notify_current_user! end end end
  • 75. class Create < Trailblazer::Operation # # # end result = Create.() result.success? #=> true
  • 76. Notes: Hooray, we have an API for service objects!
  • 78. class Create < Trailblazer::Operation # # # # end
  • 79. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify_current_user! end
  • 80.
  • 81.
  • 82. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify_current_user! end
  • 83. class Create < Trailblazer::Operation step :create_model! # # # # end
  • 84. class Create < Trailblazer::Operation step :create_model! def create_model!(options, **) end end
  • 85. CREATE MODEL class Create < Trailblazer::Operation step :create_model! def create_model!(options, **) options["model"] = BlogPost.new end end result = Create.() result.success? #=> true result["model"] #=> #<BlogPost id:nil, ..>
  • 86. VALIDATE class Create < Trailblazer::Operation step :create_model! step :validate! def create_model!(options, **) # .. def validate!(options, params:, **) # validate params end end
  • 87. valid_params = { body: "Blogging's fun. #not" } Create.( valid_params ) class Create < Trailblazer::Operation # .. def validate!(options, params:, **) params #=> { body: "Blogging's fun. #not" } end end
  • 88. Notes: sending params into the op
  • 89. class Create < Trailblazer::Operation # .. def validate!(options, params:, **) model = options["model"] # from the create_model! step... if model.update_attributes(params) true else false end end end
  • 90. class Create < Trailblazer::Operation # .. def validate!(options, params:, model:, **) # # if model.update_attributes(params) true else false end end end
  • 91.
  • 92.
  • 93.
  • 94. #class Create < Trailblazer::Operation # .. def validate!(options, params:, model:, **) if model.update_attributes(params) true else false end end #end
  • 95. #class Create < Trailblazer::Operation # .. def validate!(options, params:, model:, **) # # # # model.update_attributes(params) end #end
  • 96.
  • 97.
  • 98. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! # # # # # # end
  • 99. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! #def create_model!(options, **) #def validate!(options, params:, **) def save!(options, params:, model:, **) true end end
  • 100.
  • 101.
  • 102. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! #def create_model!(options, **) #def validate!(options, params:, **) #def save!(options, params:, model:, **) def notify!(options, model:, **) MyMailer.call(model) end end
  • 105.
  • 106. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! #def create_model!(options, **) #def validate!(options, params:, **) #def save!(options, params:, model:, **) #def notify!(options, model:, **) end
  • 107. class Create < Trailblazer::Operation step :create_model! step :validate! [XXX] step :save! step :notify! #def create_model!(options, **) #def validate!(options, params:, **) #def save!(options, params:, model:, **) #def notify!(options, model:, **) end
  • 108.
  • 109.
  • 110. #class Create < Trailblazer::Operation # .. def validate!(options, params:, model:, **) model.update_attributes(params) #=> false end #end
  • 111.
  • 112.
  • 113.
  • 114. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! failure :handle! #.. end
  • 115. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! failure :handle! #.. def handle!(options, **) options["error"] = "don't cry!" end end
  • 116. result = Create.( { title: nil } ) result.success? #=> false result["error"] = "don't cry!"
  • 119. DUDE.
  • 120.
  • 121. Notes: do you find this more complex than this?
  • 122. class MyService def call(params) return unless can?(current_user, Post, :new) post = Post.new(author: current_user) if post.update_attributes( params.require(:post).permit(:title) ) unless notify_current_user! if ... else end end end
  • 123. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! failure :handle! # .. end
  • 124. def create_model!(options, **) def validate!( options, params:, **) def save!( options, params:, model:, **) def notify!( options, model:, **)
  • 125. result = Create.( { title: nil } ) result.success? #=> false result["error"] #=> "don't cry!" result["model"] #=> #<BlogPost title: nil>
  • 126. TEST it "fails with empty title" do result = Create.( { title: nil } ) expect(result).to be_success expect(result["error"]).to eq("don't cry!") expect(result["model"]).to be_persisted end
  • 128.
  • 129.
  • 131. class PostsController < ApplicationController def create return unless can?(current_user, Post, :new) post = Post.new(author: current_user) if post.update_attributes( params.require(:post).permit(:title)) notify_current_user! else render :new end end end
  • 132. class PostsController < ApplicationController def create return unless can?(current_user, Post, :new) # # # result = BlogPost::Create.( params ) if result.failure? render :new end end end
  • 133. AUTHORIZATION def create return unless can?(current_user, Post, :new) # ..
  • 134. class Create < Trailblazer::Operation step :authorize! #step :create_model! #step :validate! #step :save! #step :notify! #failure :handle! # .. end
  • 135. class Create < Trailblazer::Operation step :authorize! # .. def authorize!(options, current_user:, **) CouldCould.can?(current_user, Post, :new) end end
  • 137. def authorize!(options, current_user:, **) CouldCould.can?( current_user, # wtf? Post, :new ) end
  • 138. class PostsController < ApplicationController def create return unless can?(current_user, Post, :new) result = BlogPost::Create.( params ) # # # if result.failure? render :new end end end
  • 139. class PostsController < ApplicationController def create return unless can?(current_user, Post, :new) result = BlogPost::Create.( params, "current_user" => current_user ) if result.failure? render :new end end end
  • 140. class PostsController < ApplicationController def create #return unless can?(current_user, Post, :new) # result = BlogPost::Create.( params, "current_user" => current_user ) if result.failure? render :new end end end
  • 141. class PostsController < ApplicationController def create result = BlogPost::Create.( params, "current_user" => current_user ) if result.failure? render :new end end end
  • 142. class PostsController < ApplicationController def create run BlogPost::Create, "current_user" => current_user do return end render :new end end
  • 143. class PostsController < ApplicationController def create run BlogPost::Create do return end render :new end end
  • 144. class PostsController < ApplicationController def create run BlogPost::Create do |result| return redirect_to blog_post_path(result["model"].id) end render :new end end
  • 145. class PostsController < ApplicationController def create run BlogPost::Create do |result| return redirect_to blog_post_path(result["model" end render :new end end
  • 146. DEPENDENCY INJECTION it "works with current_user" do result = Create.( valid_params, "current_user" => User.find(1) ) # .. end
  • 147.
  • 148.
  • 149. class Create < Trailblazer::Operation step :authorize! # .. def authorize!(options, current_user:, **) CouldCould.can?(current_user, Post, :new) end end
  • 150. class Create < Trailblazer::Operation step MyAuth # .. class MyAuth def self.call(options, current_user:, **) CouldCould.can?(current_user, Post, :new) end end end
  • 151. class Create < Trailblazer::Operation step MyAuthCallableSittingSomewhere # .. #class MyAuth # def self.call(options, current_user:, **) # CouldCould.can?(current_user, Post, :new) # end #end end
  • 153. class Create < Trailblazer::Operation step Policy::CanCan( Post, :new ) # step :model! # .. end
  • 154.
  • 155.
  • 157.
  • 158. class Post < ActiveRecord::Base validates :title, presence:true validates :body, presence:true #after_save :notify_moderators!, if: :create? end
  • 159. module BlogPost module Contract class Create::Create < Reform::Form property :title property :body validates :title, presence:true validates :body, presence:true end end end
  • 160. class Create < Trailblazer::Operation step Policy::CanCan( Post, :new ) step :model! step :validate! step :notify! # .. def model!(options, **) def validate!(options, **) # .. end
  • 161. class Create < Trailblazer::Operation step Policy::CanCan( Post, :new ) step :model! step Contract::Build( constant: Contract::Create ) step Contract::Validate() step Contract::Persist() step :notify! # .. def model!(options, **) # .. end
  • 162.
  • 163.
  • 164.
  • 165.
  • 166. BPMN
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172. class Create < Trailblazer::Operation step :create_model! step :validate! step :save! step :notify! failure :handle! # .. end
  • 173.
  • 177. [ ] DIAGRAMS [x] 6 MEMES [xX] 2 BULLET POINT LISTS [x] QUOTE FROM SOMEONE [x] MORE DIAGRAMS [ ] TRUCKLOADS OF CODE (you wanted it)