SlideShare ist ein Scribd-Unternehmen logo
1 von 77
Downloaden Sie, um offline zu lesen
TWO TRAINSAND OTHER
REFACTORING
ANALOGIES
by Kevin London
@kevin_london
ChowNow
Legacy Code
Formula:
1. No tests
2. Hard to read.
3. Hard to change.
“Any fool can write code that a
computer can understand.
Good programmers write code
that humans can understand.”
Martin Fowler
It’s
easy to create
legacy code.
How can we
prevent it?
1. Add tests.
2. Refactor.
Refactoring:
Improving design
without changing
behavior
My analogies
for refactoring:
The Trash Pile
“Who will notice if I
add this piece of
trash?”
Better to clean
as we go.
An example.
def get_tax(order):
if order.state == 'CA':
return order.subtotal * .0875
elif order.state == 'PA':
return order.subtotal * .08
else:
raise NotImplementedError()
Need to add
in Texas.
def get_tax(order):
if order.state == 'CA':
return order.subtotal * .0875
elif order.state == 'PA':
return order.subtotal * .08
elif order.state == 'TX':
return order.subtotal * .0825
else:
raise NotImplementedError()
def get_tax(order):
if order.state == 'CA':
return order.subtotal * .0875
elif order.state == 'PA':
return order.subtotal * .08
else:
raise NotImplementedError()
Add tests.
import pytest
from taxes import get_tax, Order
def test_get_tax_for_ca():
order = Order(subtotal=10, state='CA')
assert get_tax(order) == 10 * .0875
def test_get_tax_for_pa():
order = Order(subtotal=10, state='PA')
assert get_tax(order) == 10 * 0.08
def test_it_raises_error_for_others():
with pytest.raises(NotImplementedError):
order = Order(subtotal=1, state='EQ')
assert get_tax(order) == 0
Refactor.
TAXES = {
'CA': .0875,
'PA': .08,
}
def get_tax(order):
try:
return order.subtotal * TAXES[order.state]
except KeyError:
raise NotImplementedError()
============ test session starts =================
test.py ...
============ 3 passed in 0.01 seconds ============
def tax_equals_percent(state, percent):
subtotal = 10
order = Order(subtotal, state)
return get_tax(order) == subtotal *
percent
. . .
def test_get_tax_for_texas():
assert tax_equals_percent(‘TX', .0825)
. . .
============ test session starts ============
test.py ..F.
===== 1 failed, 3 passed in 0.02 seconds ====
TAXES = {
'CA': .0875,
'PA': .08,
'TX': .0825,
}
def get_tax(order):
try:
return order.subtotal * TAXES[order.state]
except KeyError:
raise NotImplementedError()
============ test session starts =================
test.py ....
============ 4 passed in 0.01 seconds ============
Make it
better
over time.
Tube of
Toothpaste
Easy to get toothpaste
from a new tube.
At the end,
need to roll it to get
toothpaste
With Code:
Make it easy to
change.
“For each desired change:
make the change easy
(warning: this may be hard),
then make the easy change.”
Kent Beck
class User:
def __init__(self, data):
self.data = data
def validate(self):
if '@' not in self.data['email']:
raise ValueError('Invalid email provided.')
if len(self.data['first_name']) > 50:
raise ValueError('First name too long.')
if len(self.data['last_name']) > 100:
raise ValueError('Last name too long.')
Change:
Validate phone number
import pytest
def assert_raises_error(data, expected_message):
user = User(data=data)
with pytest.raises(ValueError) as excinfo:
user.validate()
assert expected_message in str(excinfo.value)
class TestValidateUser:
def test_invalid_email_raises_error(self):
data = {
'first_name': 'foo',
'email': 'bademail',
'last_name': 'lee',
}
assert_raises_error(data, 'Invalid email provided')
. . .
=========== test session starts =======
test.py ...
======== 3 passed in 0.01 seconds=====
Make the
change easy.
class User:
def __init__(self, data):
self.data = data
def validate(self):
self.validate_email()
self.validate_first_name()
self.validate_last_name()
def validate_email(self):
if '@' not in self.data['email']:
raise ValueError('Invalid email provided.')
def validate_first_name(self):
if len(self.data['first_name']) > 50:
raise ValueError('First name too long.')
def validate_last_name(self):
if len(self.data['last_name']) > 100:
raise ValueError('Last name too long.')
=========== test session starts =======
test.py ...
======== 3 passed in 0.01 seconds=====
class User:
_fields = [
'email',
'first_name',
'last_name'
]
def __init__(self, data):
self.data = data
def validate(self):
for field in self._fields:
method_name = 'validate_{}'.format(field)
validate_field = getattr(self, method_name)
validate_field()
def validate_email(self):
. . .
=========== test session starts =======
test.py ...
======== 3 passed in 0.01 seconds=====
Make the
easy change.
class TestValidateUser:
. . .
def test_invalid_phone_number_raises_error(self):
data = {'phone_number': 'no_phone'}
user = User(data)
with pytest.raises(ValueError):
user.validate_phone_number()
=========== test session starts =======
test.py ...F
== 1 failed, 3 passed in 0.01 seconds==
class User:
_fields = [
'email',
'first_name',
'last_name',
'phone_number',
]
PHONE_LENGTH = 10
. . .
def validate_phone_number(self):
if len(self.data['phone_number']) != User.PHONE_LENGTH:
raise ValueError('Phone number is wrong length.')
=========== test session starts =======
test.py ....
======== 4 passed in 0.01 seconds======
By refactoring,
we make it easy to
change the code.
The Two
Trains
Need to
jump.
The nuclear
option:
rewrite
With code:
1. Reach Parity
2. Switch
3. Improve
A story about a
failed rewrite.
Let’s say we’re
switching
languages.
PHP -> Python
<?php
if (isset($_GET['fahrenheit'])) {
$fahrenheit = $_GET['fahrenheit'];
} else {
die('No degrees in Fahrenheit provided.');
}
$celsius = ($fahrenheit - 32) * 5 / 9;
echo floor($celsius);
1. Add tests.
2. Refactor.
import requests
API_URL = 'http://localhost:8888/celsius'
def test_api_converts_fahrenheit():
degrees_f = 32
degrees_c = 0
path = '{}?fahrenheit={}'.format(API_URL, degrees_f)
response = requests.get(path)
assert int(response.content) == degrees_c
def test_api_rounds_down():
degrees_f = 100
degrees_c = 37 # rounded down
path = '{}?fahrenheit={}'.format(API_URL, degrees_f)
response = requests.get(path)
assert int(response.content) == degrees_c
def test_api_returns_error_if_no_degrees():
response = requests.get(API_URL)
assert 'No degrees' in response.content
=========== test session starts =======
test_php_api.py ...
======== 3 passed in 0.01 seconds=====
Rewrite the
code.
import requests
API_URL = 'http://localhost:5000/celsius'
. . .
=========== test session starts =======
test_py_api.py FFF
======== 3 failed in 0.01 seconds=====
Get the tests
passing again
from math import floor
from flask import Flask, request
app = Flask(__name__)
@app.route('/celsius')
def celsius():
try:
fahrenheit = int(request.args.get('fahrenheit'))
except TypeError:
return 'No degrees in Fahrenheit provided.'
celsius = (fahrenheit - 32) * 5 / 9;
return str(floor(celsius))
=========== test session starts =======
test_py_api.py ...
======== 3 passed in 0.01 seconds=====
Reaching parity
reduces risk.
the smaller
the switch,
the better.
IN REVIEW
Don’t treat code like
a pile of trash.
Clean it up as you go.
Remember the tube of
toothpaste:
Make the change easy,
make the easy change.
If you have to jump
across two trains,
Get them to the same
speed & switch.
We can change
how we think
about legacy
code.
Technical
debt
Technical
wealth
Improving
code pays
dividends.
References:
Refactoring - Martin Fowler & Kent Beck
https://www.amazon.com/Refactoring-Improving-Design-Existing-
Code/dp/B007WTFWJ6/ref=sr_1_1?
s=books&ie=UTF8&qid=1472533198&sr=1-1&keywords=refactori
ng+martin+fowler#nav-subnav
Working with Legacy Code - Michael Feathers
https://www.amazon.com/Working-Effectively-Legacy-Michael-
Feathers/dp/0131177052
Forget Technical Debt — Here's How to Build
Technical Wealth
http://firstround.com/review/forget-technical-debt-heres-how-to-
build-technical-wealth/
Credits:
IMG_5163 - Justin Henry, https://flic.kr/p/ebaYR
The sky is the limit #2 - Mark Dries, https://flic.kr/p/eeq2eQ
The way it should be! - Patrick Dirden, https://flic.kr/p/
8Yp4mf
0001_zoriah_photojournalist_war_photographer_20120719
_0631 - Zoriah, https://flic.kr/p/dkScaB
Freaktography - Ravaged, https://flic.kr/p/nh72Tp
Aachen - Aachener Dom Pala d’oro Antependium - Daniel
Mennerich, https://flic.kr/p/pBmHyw
Thank you!
Slides:
http://bit.ly/twotrains
www.kevinlondon.com
@kevin_london

Weitere ähnliche Inhalte

Was ist angesagt?

Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesNaresha K
 
The Ring programming language version 1.4 book - Part 11 of 30
The Ring programming language version 1.4 book - Part 11 of 30The Ring programming language version 1.4 book - Part 11 of 30
The Ring programming language version 1.4 book - Part 11 of 30Mahmoud Samir Fayed
 
Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015CiaranMcNulty
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
ngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionDzmitry Ivashutsin
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...GeeksLab Odessa
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"GeeksLab Odessa
 
4 mishchevskii - testing stage18-
4   mishchevskii - testing stage18-4   mishchevskii - testing stage18-
4 mishchevskii - testing stage18-Ievgenii Katsan
 
focuslight-validator validate sinatra application - validation night at LINE ...
focuslight-validator validate sinatra application - validation night at LINE ...focuslight-validator validate sinatra application - validation night at LINE ...
focuslight-validator validate sinatra application - validation night at LINE ...Satoshi Suzuki
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기Yeongseon Choe
 
Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobCiaranMcNulty
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестированияMitinPavel
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Dhaval Dalal
 

Was ist angesagt? (20)

Advanced Developer Testing
Advanced Developer TestingAdvanced Developer Testing
Advanced Developer Testing
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good Practices
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
The Ring programming language version 1.4 book - Part 11 of 30
The Ring programming language version 1.4 book - Part 11 of 30The Ring programming language version 1.4 book - Part 11 of 30
The Ring programming language version 1.4 book - Part 11 of 30
 
Refactoring
RefactoringRefactoring
Refactoring
 
Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015
 
Refactoring
RefactoringRefactoring
Refactoring
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
ngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency Injection
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
 
4 mishchevskii - testing stage18-
4   mishchevskii - testing stage18-4   mishchevskii - testing stage18-
4 mishchevskii - testing stage18-
 
focuslight-validator validate sinatra application - validation night at LINE ...
focuslight-validator validate sinatra application - validation night at LINE ...focuslight-validator validate sinatra application - validation night at LINE ...
focuslight-validator validate sinatra application - validation night at LINE ...
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
 
Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the Job
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
 
React lecture
React lectureReact lecture
React lecture
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
Next Level Testing Revisited
Next Level Testing RevisitedNext Level Testing Revisited
Next Level Testing Revisited
 

Andere mochten auch

Juego de alimentación para niños de 6 años
Juego de alimentación para niños de 6 añosJuego de alimentación para niños de 6 años
Juego de alimentación para niños de 6 añosPatricia marcos
 
Supervisor variance in psychotherapy outcome in routine practice (psychothera...
Supervisor variance in psychotherapy outcome in routine practice (psychothera...Supervisor variance in psychotherapy outcome in routine practice (psychothera...
Supervisor variance in psychotherapy outcome in routine practice (psychothera...Daryl Chow
 
у нашій школі є шкільне самоврядування яке складається з
у нашій школі є шкільне самоврядування яке складається зу нашій школі є шкільне самоврядування яке складається з
у нашій школі є шкільне самоврядування яке складається зvikusikv12
 
CMaxwell-Miller_Research Proposal_041716_pptx
CMaxwell-Miller_Research Proposal_041716_pptxCMaxwell-Miller_Research Proposal_041716_pptx
CMaxwell-Miller_Research Proposal_041716_pptxChevelle Maxwell-Miller
 
Rajeev_R_CV Updated
Rajeev_R_CV UpdatedRajeev_R_CV Updated
Rajeev_R_CV UpdatedRAJEEV R
 
Pricing Team
Pricing TeamPricing Team
Pricing TeamNeha Jain
 
aviation_resume_-_Copy_-_Copy_converted
aviation_resume_-_Copy_-_Copy_convertedaviation_resume_-_Copy_-_Copy_converted
aviation_resume_-_Copy_-_Copy_convertedwalter fernandez
 
Noción de estructura socioeconómica
Noción de estructura socioeconómicaNoción de estructura socioeconómica
Noción de estructura socioeconómicaIsrael Pacheco
 
Reach slides handout day I (2 slides per pg miller & chow, 16)
Reach slides handout day I (2 slides per pg miller & chow, 16)Reach slides handout day I (2 slides per pg miller & chow, 16)
Reach slides handout day I (2 slides per pg miller & chow, 16)Daryl Chow
 
Dokumen satu
Dokumen satuDokumen satu
Dokumen satusatusama
 

Andere mochten auch (15)

Juego de alimentación para niños de 6 años
Juego de alimentación para niños de 6 añosJuego de alimentación para niños de 6 años
Juego de alimentación para niños de 6 años
 
Supervisor variance in psychotherapy outcome in routine practice (psychothera...
Supervisor variance in psychotherapy outcome in routine practice (psychothera...Supervisor variance in psychotherapy outcome in routine practice (psychothera...
Supervisor variance in psychotherapy outcome in routine practice (psychothera...
 
у нашій школі є шкільне самоврядування яке складається з
у нашій школі є шкільне самоврядування яке складається зу нашій школі є шкільне самоврядування яке складається з
у нашій школі є шкільне самоврядування яке складається з
 
Black jack ppt
Black jack pptBlack jack ppt
Black jack ppt
 
CMaxwell-Miller_Research Proposal_041716_pptx
CMaxwell-Miller_Research Proposal_041716_pptxCMaxwell-Miller_Research Proposal_041716_pptx
CMaxwell-Miller_Research Proposal_041716_pptx
 
Rajeev_R_CV Updated
Rajeev_R_CV UpdatedRajeev_R_CV Updated
Rajeev_R_CV Updated
 
Pricing Team
Pricing TeamPricing Team
Pricing Team
 
Formato de evaluación sesion 4
Formato de evaluación sesion 4Formato de evaluación sesion 4
Formato de evaluación sesion 4
 
aviation_resume_-_Copy_-_Copy_converted
aviation_resume_-_Copy_-_Copy_convertedaviation_resume_-_Copy_-_Copy_converted
aviation_resume_-_Copy_-_Copy_converted
 
Noción de estructura socioeconómica
Noción de estructura socioeconómicaNoción de estructura socioeconómica
Noción de estructura socioeconómica
 
Afgang Eksp
Afgang EkspAfgang Eksp
Afgang Eksp
 
Luz miriam jimenez garcia
Luz miriam jimenez garciaLuz miriam jimenez garcia
Luz miriam jimenez garcia
 
Reach slides handout day I (2 slides per pg miller & chow, 16)
Reach slides handout day I (2 slides per pg miller & chow, 16)Reach slides handout day I (2 slides per pg miller & chow, 16)
Reach slides handout day I (2 slides per pg miller & chow, 16)
 
EikenTALENT2016 azalpena
EikenTALENT2016 azalpenaEikenTALENT2016 azalpena
EikenTALENT2016 azalpena
 
Dokumen satu
Dokumen satuDokumen satu
Dokumen satu
 

Ähnlich wie Two Trains and Other Refactoring Analogies

Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2markstory
 
Pruebas unitarias con django
Pruebas unitarias con djangoPruebas unitarias con django
Pruebas unitarias con djangoTomás Henríquez
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Frédéric Delorme
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Mock Hell PyCon DE and PyData Berlin 2019
Mock Hell PyCon DE and PyData Berlin 2019Mock Hell PyCon DE and PyData Berlin 2019
Mock Hell PyCon DE and PyData Berlin 2019Edwin Jung
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
Tips and tricks for building api heavy ruby on rails applications
Tips and tricks for building api heavy ruby on rails applicationsTips and tricks for building api heavy ruby on rails applications
Tips and tricks for building api heavy ruby on rails applicationsTim Cull
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven DevelopmentKerry Buckley
 
Testing most things in JavaScript - LeedsJS 31/05/2017
Testing most things in JavaScript - LeedsJS 31/05/2017Testing most things in JavaScript - LeedsJS 31/05/2017
Testing most things in JavaScript - LeedsJS 31/05/2017Colin Oakley
 
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 JasminePaulo Ragonha
 

Ähnlich wie Two Trains and Other Refactoring Analogies (20)

Why Our Code Smells
Why Our Code SmellsWhy Our Code Smells
Why Our Code Smells
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Pruebas unitarias con django
Pruebas unitarias con djangoPruebas unitarias con django
Pruebas unitarias con django
 
TDD, BDD and mocks
TDD, BDD and mocksTDD, BDD and mocks
TDD, BDD and mocks
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Mock Hell PyCon DE and PyData Berlin 2019
Mock Hell PyCon DE and PyData Berlin 2019Mock Hell PyCon DE and PyData Berlin 2019
Mock Hell PyCon DE and PyData Berlin 2019
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Tips and tricks for building api heavy ruby on rails applications
Tips and tricks for building api heavy ruby on rails applicationsTips and tricks for building api heavy ruby on rails applications
Tips and tricks for building api heavy ruby on rails applications
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Development
 
Django (Web Konferencia 2009)
Django (Web Konferencia 2009)Django (Web Konferencia 2009)
Django (Web Konferencia 2009)
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
 
Testing most things in JavaScript - LeedsJS 31/05/2017
Testing most things in JavaScript - LeedsJS 31/05/2017Testing most things in JavaScript - LeedsJS 31/05/2017
Testing most things in JavaScript - LeedsJS 31/05/2017
 
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
 
Leveraging Symfony2 Forms
Leveraging Symfony2 FormsLeveraging Symfony2 Forms
Leveraging Symfony2 Forms
 

Kürzlich hochgeladen

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
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 AutomationSafe Software
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
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 WorkerThousandEyes
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
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...Igalia
 
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 textsMaria Levchenko
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 

Kürzlich hochgeladen (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
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
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
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
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
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...
 
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
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 

Two Trains and Other Refactoring Analogies