SlideShare a Scribd company logo
SUCCESS STORY: HOW TO SWITCH STACK WITHOUT DOWNTIME
THE LEADER OF URBAN & ON-DEMAND LOGISTICS
Our mission is to connect merchants,
customers and local couriers to speed-up
the way goods are transported in cities
04
MERCHANTS TRUST US
GROWING LIST OF TOP-TIER REFERENCES ACROSS VERTICALS
05
TEAM
GROWING AND TALENTED ORGANISATION
CLÉMENT BENOIT
Co-Founder & CEO
Resto-in founder
BENJAMIN CHEMLA
Co-Founder & VP
Sales
Citycake founder
DAMIEN BON
COO
BCG
INSEAD
Lehman Brothers
FABIEN PENSO
CTO
Process-One
CloudScreener
Causes
We manage a team of 80 people coming from the best companies
06
ABOUT ME
1995: Started using Linux
1998: LinuxFr - a French Linux community website
1999: DBee - First company
Since 2010: Causes, BBC, Cloudscreener, Stuart
PAST EXPERIENCES
@fabienpenso
http://penso.info
Short Video
08
INFRASTRUCTURE 2015
09
SOFTWARE STACK 2015
Standard LAMP + RabbitMQ + Crontab
0% test
coverage
GPA: 3.40 90k LOC 150 SQL
tables
10
API REQUESTS PROCESSED IN 2015
SLOW PHP REQUEST
PROCESSING
(INCLUDES PSEUDO
BACKGROUND
TASKS)
REACH MAX
AMOUNT OF PHP
PROCESSES
QUICKLY
MINIMUM INTERVAL
FOR TASKS IS 1
MINUTE
INEFFICIENT
STORAGE FOR
BACKGROUND
TASKS
11
LOOKING FOR A NEW STACK OPTION
12
HOW TO SWITCH: TWO PATHWAYS
Option A
Write all from the ground up,
new Rails project, then write a
script to move all existing data.
+ Clean code, no legacy
once moved.
- Can't rollback, long time
before seeing
improvements
- High chance of failure
Option B
Write small pieces of code to
work with the existing context/
environment.
+ Business doesn't stop,
can still add features, and
fix existing bugs
- Manage 2 platforms for
months, new code
connects to old storage
schema, must replicate
bad code structure
13
QUICK CODE GENERATION
Automatic code generation - ActiveRecord Ruby
code from SQL tables
Backoffice - Install ActiveAdmin to view all AR
classes and records
Continuous Integration - Setup deployment
Gem - php_serialize, annotate, devise
# == Schema Information
#
# Table name: vehicle
#
# id :integer not null, primary key
# driver_id :integer
# brand :string(100)
# model :string(150)
# number_plate :string(20)
# color :string(45)
# insurance :string(255)
# vehicle_registration :string(255)
class Vehicle < ActiveRecord::Base
end
14
RUNNING BOTH PLATFORM
Refactor Feature Flag Ruby Feedback
Encapsulate the
PHP feature within
a single function
call
Add a feature flag in
the PHP code to enable/
disable this call
QA team enable
the feature on
staging, and verify
it works as
expected
Implement the
next "feature"
Clone code in
Ruby, add an
opposite feature
flag
15
IMPLEMENTING NEW CODE
Production
16
HAVE A PLAN
Split the legacy
codebase into
virtual modules
Rewrite an easy
one at first
Rewrite them in
order of
importance
Finish with low
priority non critical
code
17
IMPROVE LEGACY CODE
Add AR model validation
class Job < ActiveRecord::Base
validates :expires_at, presence: true
validate :payment_ability, on: :create
def payment_ability
if !has_funds? && !credit_card
errors.add(:credit_card, "meaningful message")
end
end
end
Ruby
Run validation for every SQL
changes
Warn about invalid models on Slack
<?php
// … code
class EntityListener {
protected $sidekiqJobPusher;
public function __construct(TransactionQueueService $redisClient) {
$this->sidekiqJobPusher = $redisClient;
}
public function onUpdate($calledEntity, UnitOfWork $uow) {
$this->sidekiqJobPusher->performActiveJob("PhpJob",
[$calledEntityName, $id, 'php_after_updated', $changedValues], true, "php");
}
public function onInsert($calledEntity) {
$this->sidekiqJobPusher->performActiveJob("PhpJob",
[$calledEntityName, $id, 'php_after_created'], true, "php");
}
}
?>
PHP Method injections
18
IMPROVE LEGACY CODE
# app/models/concerns/php_callbacks.rb
module PhpCallbacks
def php_after_created(_options = {})
return if valid?
message = "#{self.class}: #{id} errors: #{errors.full_messages.to_sentence}"
Service::Slack.ping message, channel: "#exceptions-#{Rails.env}"
end
alias php_after_updated php_after_created
End
# app/jobs/php_job.rb
class PhpJob < ActiveJob::Base
queue_as :php
include JobLogger
ACCEPTED_METHODS = %w(php_after_updated php_after_created).freeze
def perform(klass_type, id, method, *args)
unless ACCEPTED_METHODS.include?(method)
raise ArgumentError.new("`method` can only be #{ACCEPTED_METHODS.join(' or ')}!")
end
klass = klass_type.constantize rescue nil
if klass && klass.method_defined?(method.to_sym)
object = klass.find(id)
object.send(method, *args)
end
end
end
Ruby validation execution
19
IMPROVE LEGACY CODE
20
FEATURE FLAG
FEATURE FLAG: ABILITY TO TURN FEATURE ON/OFF
PHP
use OpensoftRolloutRollout;

use OpensoftRolloutStorageArrayStorage;


$rollout = new Rollout(new ArrayStorage());
$rollout->isActive('outgoing_email');
Ruby
require "redis"

require "rollout"

$redis = Redis.new

$rollout = Rollout.new($redis)
$rollout.active?(:outgoing_email)
https://github.com/opensoft/rollout (PHP)
https://github.com/fetlife/rollout (Ruby)
21
REMOVE OVERENGINEERED CODE
TOO MANY SQL TABLES
Before: 150 tables
After: 90 tables
class DriverStatusType
include TypableModel
read_only_attr :id, :code, :name
defaults [
[1, "off_duty", "Off Duty"],
[2, "on_duty", "On Duty"],
[3, "busy", "Busy"],
[4, "pending", "Pending"],
[5, "rejected", "Rejected"]
]
end
DriverStatusType.find_by(id: 1)
DriverStatusType.find_by(code: :on_duty)
22
MOVE API ENDPOINTS
List ALL API
endpoints currently
used looking at the
PHP logs
68 endpoints to move
Make a plan
23
MOVE API ENDPOINTS
Move one non critical
API endpoint
Move by importance,
most critical first
Good potential: https://getkong.org
Be able to turn each
api endpoint on/off
Grape Routing Feedback
Implement the API
endpoint in Ruby
Move this API
endpoint to Ruby in the
nginx routing file on
staging
Implement the
next api endpoint
QA team verify it
works as
expected
24
MOVE API ENDPOINTS
Production
25
MOVE API ENDPOINTS
TOOLS: LIST OUR QA USED FOR TESTING
Runscope.com
Selenium
Android Espresso
iOS xcode test
Postman and curl
Charles HTTP Proxy
26
INFRASTRUCTURE 2016
27
CLOSING: SOFTWARE STACK 2015
Standard LAMP + RabbitMQ + Crontab
0% test
coverage
GPA: 3.40 90k LOC 150 SQL
tables
28
CLOSING: SOFTWARE STACK 2016
Grape + Sidekiq + Rails
70% test
coverage
GPA: 3.95 15k LOC 90 SQL
tables
How long to move all the
code
?
30
CLOSING
ROOM FOR IMPROVEMENT: WHAT WOULD WE DO DIFFERENT?
Ability to have ephemeral servers Give more power to the QA
Engineers
@fabienpenso

More Related Content

Similar to How to switch stack without downtime

IBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js MicroservicesIBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
Chris Bailey
 
Mac ruby deployment
Mac ruby deploymentMac ruby deployment
Mac ruby deployment
Thilo Utke
 
Managing the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS LambdaManaging the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS Lambda
Amazon Web Services
 
The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)
Michiel Rook
 
Developer intro to open shift
Developer intro to open shiftDeveloper intro to open shift
Developer intro to open shift
Ram Maddali
 
Automate Your Automation | DrupalCon Vienna
Automate Your Automation | DrupalCon ViennaAutomate Your Automation | DrupalCon Vienna
Automate Your Automation | DrupalCon Vienna
Pantheon
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
C4Media
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Henning Jacobs
 
Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...
Luciano Mammino
 
Fast Web Applications Development with Ruby on Rails on Oracle
Fast Web Applications Development with Ruby on Rails on OracleFast Web Applications Development with Ruby on Rails on Oracle
Fast Web Applications Development with Ruby on Rails on Oracle
Raimonds Simanovskis
 
Docker In Bank Unrated
Docker In Bank UnratedDocker In Bank Unrated
Docker In Bank Unrated
Aleksandr Tarasov
 
Serverless in Production, an experience report (cloudXchange)
Serverless in Production, an experience report (cloudXchange)Serverless in Production, an experience report (cloudXchange)
Serverless in Production, an experience report (cloudXchange)
Yan Cui
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0
Eugenio Romano
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containers
inside-BigData.com
 
Serverless in production, an experience report (LNUG)
Serverless in production, an experience report (LNUG)Serverless in production, an experience report (LNUG)
Serverless in production, an experience report (LNUG)
Yan Cui
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-ServicesNode Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Chris Bailey
 
Federico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesFederico Feroldi - Scala microservices
Federico Feroldi - Scala microservices
Scala Italy
 
AWS Lambda from the trenches
AWS Lambda from the trenchesAWS Lambda from the trenches
AWS Lambda from the trenches
Yan Cui
 
Serverless in production, an experience report (CoDe-Conf)
Serverless in production, an experience report (CoDe-Conf)Serverless in production, an experience report (CoDe-Conf)
Serverless in production, an experience report (CoDe-Conf)
Yan Cui
 
From Code to Cloud - PHP on Red Hat's OpenShift
From Code to Cloud - PHP on Red Hat's OpenShiftFrom Code to Cloud - PHP on Red Hat's OpenShift
From Code to Cloud - PHP on Red Hat's OpenShift
Eric D. Schabell
 

Similar to How to switch stack without downtime (20)

IBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js MicroservicesIBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
 
Mac ruby deployment
Mac ruby deploymentMac ruby deployment
Mac ruby deployment
 
Managing the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS LambdaManaging the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS Lambda
 
The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)
 
Developer intro to open shift
Developer intro to open shiftDeveloper intro to open shift
Developer intro to open shift
 
Automate Your Automation | DrupalCon Vienna
Automate Your Automation | DrupalCon ViennaAutomate Your Automation | DrupalCon Vienna
Automate Your Automation | DrupalCon Vienna
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
Why Kubernetes? Cloud Native and Developer Experience at Zalando - OWL Tech &...
 
Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...
 
Fast Web Applications Development with Ruby on Rails on Oracle
Fast Web Applications Development with Ruby on Rails on OracleFast Web Applications Development with Ruby on Rails on Oracle
Fast Web Applications Development with Ruby on Rails on Oracle
 
Docker In Bank Unrated
Docker In Bank UnratedDocker In Bank Unrated
Docker In Bank Unrated
 
Serverless in Production, an experience report (cloudXchange)
Serverless in Production, an experience report (cloudXchange)Serverless in Production, an experience report (cloudXchange)
Serverless in Production, an experience report (cloudXchange)
 
Let's play with adf 3.0
Let's play with adf 3.0Let's play with adf 3.0
Let's play with adf 3.0
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containers
 
Serverless in production, an experience report (LNUG)
Serverless in production, an experience report (LNUG)Serverless in production, an experience report (LNUG)
Serverless in production, an experience report (LNUG)
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-ServicesNode Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
 
Federico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesFederico Feroldi - Scala microservices
Federico Feroldi - Scala microservices
 
AWS Lambda from the trenches
AWS Lambda from the trenchesAWS Lambda from the trenches
AWS Lambda from the trenches
 
Serverless in production, an experience report (CoDe-Conf)
Serverless in production, an experience report (CoDe-Conf)Serverless in production, an experience report (CoDe-Conf)
Serverless in production, an experience report (CoDe-Conf)
 
From Code to Cloud - PHP on Red Hat's OpenShift
From Code to Cloud - PHP on Red Hat's OpenShiftFrom Code to Cloud - PHP on Red Hat's OpenShift
From Code to Cloud - PHP on Red Hat's OpenShift
 

Recently uploaded

Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
Alberto Brandolini
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
SQL Accounting Software Brochure Malaysia
SQL Accounting Software Brochure MalaysiaSQL Accounting Software Brochure Malaysia
SQL Accounting Software Brochure Malaysia
GohKiangHock
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
Rakesh Kumar R
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
VALiNTRY360
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
ICS
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
Mobile app Development Services | Drona Infotech
Mobile app Development Services  | Drona InfotechMobile app Development Services  | Drona Infotech
Mobile app Development Services | Drona Infotech
Drona Infotech
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
Yara Milbes
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
Rakesh Kumar R
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Julian Hyde
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理
dakas1
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 

Recently uploaded (20)

Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
SQL Accounting Software Brochure Malaysia
SQL Accounting Software Brochure MalaysiaSQL Accounting Software Brochure Malaysia
SQL Accounting Software Brochure Malaysia
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
Mobile app Development Services | Drona Infotech
Mobile app Development Services  | Drona InfotechMobile app Development Services  | Drona Infotech
Mobile app Development Services | Drona Infotech
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 

How to switch stack without downtime

  • 1. SUCCESS STORY: HOW TO SWITCH STACK WITHOUT DOWNTIME
  • 2. THE LEADER OF URBAN & ON-DEMAND LOGISTICS
  • 3. Our mission is to connect merchants, customers and local couriers to speed-up the way goods are transported in cities
  • 4. 04 MERCHANTS TRUST US GROWING LIST OF TOP-TIER REFERENCES ACROSS VERTICALS
  • 5. 05 TEAM GROWING AND TALENTED ORGANISATION CLÉMENT BENOIT Co-Founder & CEO Resto-in founder BENJAMIN CHEMLA Co-Founder & VP Sales Citycake founder DAMIEN BON COO BCG INSEAD Lehman Brothers FABIEN PENSO CTO Process-One CloudScreener Causes We manage a team of 80 people coming from the best companies
  • 6. 06 ABOUT ME 1995: Started using Linux 1998: LinuxFr - a French Linux community website 1999: DBee - First company Since 2010: Causes, BBC, Cloudscreener, Stuart PAST EXPERIENCES @fabienpenso http://penso.info
  • 9. 09 SOFTWARE STACK 2015 Standard LAMP + RabbitMQ + Crontab 0% test coverage GPA: 3.40 90k LOC 150 SQL tables
  • 10. 10 API REQUESTS PROCESSED IN 2015 SLOW PHP REQUEST PROCESSING (INCLUDES PSEUDO BACKGROUND TASKS) REACH MAX AMOUNT OF PHP PROCESSES QUICKLY MINIMUM INTERVAL FOR TASKS IS 1 MINUTE INEFFICIENT STORAGE FOR BACKGROUND TASKS
  • 11. 11 LOOKING FOR A NEW STACK OPTION
  • 12. 12 HOW TO SWITCH: TWO PATHWAYS Option A Write all from the ground up, new Rails project, then write a script to move all existing data. + Clean code, no legacy once moved. - Can't rollback, long time before seeing improvements - High chance of failure Option B Write small pieces of code to work with the existing context/ environment. + Business doesn't stop, can still add features, and fix existing bugs - Manage 2 platforms for months, new code connects to old storage schema, must replicate bad code structure
  • 13. 13 QUICK CODE GENERATION Automatic code generation - ActiveRecord Ruby code from SQL tables Backoffice - Install ActiveAdmin to view all AR classes and records Continuous Integration - Setup deployment Gem - php_serialize, annotate, devise # == Schema Information # # Table name: vehicle # # id :integer not null, primary key # driver_id :integer # brand :string(100) # model :string(150) # number_plate :string(20) # color :string(45) # insurance :string(255) # vehicle_registration :string(255) class Vehicle < ActiveRecord::Base end
  • 15. Refactor Feature Flag Ruby Feedback Encapsulate the PHP feature within a single function call Add a feature flag in the PHP code to enable/ disable this call QA team enable the feature on staging, and verify it works as expected Implement the next "feature" Clone code in Ruby, add an opposite feature flag 15 IMPLEMENTING NEW CODE Production
  • 16. 16 HAVE A PLAN Split the legacy codebase into virtual modules Rewrite an easy one at first Rewrite them in order of importance Finish with low priority non critical code
  • 17. 17 IMPROVE LEGACY CODE Add AR model validation class Job < ActiveRecord::Base validates :expires_at, presence: true validate :payment_ability, on: :create def payment_ability if !has_funds? && !credit_card errors.add(:credit_card, "meaningful message") end end end Ruby Run validation for every SQL changes Warn about invalid models on Slack
  • 18. <?php // … code class EntityListener { protected $sidekiqJobPusher; public function __construct(TransactionQueueService $redisClient) { $this->sidekiqJobPusher = $redisClient; } public function onUpdate($calledEntity, UnitOfWork $uow) { $this->sidekiqJobPusher->performActiveJob("PhpJob", [$calledEntityName, $id, 'php_after_updated', $changedValues], true, "php"); } public function onInsert($calledEntity) { $this->sidekiqJobPusher->performActiveJob("PhpJob", [$calledEntityName, $id, 'php_after_created'], true, "php"); } } ?> PHP Method injections 18 IMPROVE LEGACY CODE
  • 19. # app/models/concerns/php_callbacks.rb module PhpCallbacks def php_after_created(_options = {}) return if valid? message = "#{self.class}: #{id} errors: #{errors.full_messages.to_sentence}" Service::Slack.ping message, channel: "#exceptions-#{Rails.env}" end alias php_after_updated php_after_created End # app/jobs/php_job.rb class PhpJob < ActiveJob::Base queue_as :php include JobLogger ACCEPTED_METHODS = %w(php_after_updated php_after_created).freeze def perform(klass_type, id, method, *args) unless ACCEPTED_METHODS.include?(method) raise ArgumentError.new("`method` can only be #{ACCEPTED_METHODS.join(' or ')}!") end klass = klass_type.constantize rescue nil if klass && klass.method_defined?(method.to_sym) object = klass.find(id) object.send(method, *args) end end end Ruby validation execution 19 IMPROVE LEGACY CODE
  • 20. 20 FEATURE FLAG FEATURE FLAG: ABILITY TO TURN FEATURE ON/OFF PHP use OpensoftRolloutRollout;
 use OpensoftRolloutStorageArrayStorage; 
 $rollout = new Rollout(new ArrayStorage()); $rollout->isActive('outgoing_email'); Ruby require "redis"
 require "rollout"
 $redis = Redis.new
 $rollout = Rollout.new($redis) $rollout.active?(:outgoing_email) https://github.com/opensoft/rollout (PHP) https://github.com/fetlife/rollout (Ruby)
  • 21. 21 REMOVE OVERENGINEERED CODE TOO MANY SQL TABLES Before: 150 tables After: 90 tables class DriverStatusType include TypableModel read_only_attr :id, :code, :name defaults [ [1, "off_duty", "Off Duty"], [2, "on_duty", "On Duty"], [3, "busy", "Busy"], [4, "pending", "Pending"], [5, "rejected", "Rejected"] ] end DriverStatusType.find_by(id: 1) DriverStatusType.find_by(code: :on_duty)
  • 22. 22 MOVE API ENDPOINTS List ALL API endpoints currently used looking at the PHP logs 68 endpoints to move Make a plan
  • 23. 23 MOVE API ENDPOINTS Move one non critical API endpoint Move by importance, most critical first Good potential: https://getkong.org Be able to turn each api endpoint on/off
  • 24. Grape Routing Feedback Implement the API endpoint in Ruby Move this API endpoint to Ruby in the nginx routing file on staging Implement the next api endpoint QA team verify it works as expected 24 MOVE API ENDPOINTS Production
  • 25. 25 MOVE API ENDPOINTS TOOLS: LIST OUR QA USED FOR TESTING Runscope.com Selenium Android Espresso iOS xcode test Postman and curl Charles HTTP Proxy
  • 27. 27 CLOSING: SOFTWARE STACK 2015 Standard LAMP + RabbitMQ + Crontab 0% test coverage GPA: 3.40 90k LOC 150 SQL tables
  • 28. 28 CLOSING: SOFTWARE STACK 2016 Grape + Sidekiq + Rails 70% test coverage GPA: 3.95 15k LOC 90 SQL tables
  • 29. How long to move all the code ?
  • 30. 30 CLOSING ROOM FOR IMPROVEMENT: WHAT WOULD WE DO DIFFERENT? Ability to have ephemeral servers Give more power to the QA Engineers