SlideShare a Scribd company logo
Assemble Your Code in Stages:
Leveling Up With Pipelines
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
About me
Steven Wade

• Husband, father

• Founder/Organizer of UpstatePHP

Twitter: @stevenwadejr

Email: stevenwadejr@gmail.com
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
// Calculate shipping
// Free shipping on orders $100+
if ($order->order_total < 100) {
$calculator = new ShippingCalculator;
$shipping = $calculator->calculate($order->shipping);
$order->order_total += $shipping;
}
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Problem
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add coupons
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
// Calculate shipping
// Free shipping on orders $100+
if ($order->order_total < 100) {
$calculator = new ShippingCalculator;
$shipping = $calculator->calculate($order->shipping);
$order->order_total += $shipping;
}
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Pipelines!*(possibly)
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Goals
• Understand what a pipeline is, and what stages are

• Learn to recognize a pipeline in our code

• Refactor code to stages

• See how stages make testing easier

• Understand when a pipeline is not the appropriate option
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
What is a pipeline?
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
|
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
cat logs.txt | grep "ERROR" | wc -l
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
So, what is a pipeline?
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Pipeline
A series of processes chained together to where
the output of each is the input of the next
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Stages
cat logs.txt | grep "ERROR" | wc -l
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Real World Example
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Bedtime
<?php
$bedtime = (new Pipeline)
->pipe(new Bath)
->pipe(new Diaper)
->pipe(new Pajamas)
->pipe(new BrushTeeth)
->pipe(new Book('Catalina Magdalena...'))
->pipe(new Song('Radio Gaga'));
$bedtime->process($penny);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Gulp
gulp.task('css', function(){
return gulp.src('client/templates/*.less')
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest('build/css'))
});
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
PHP Land
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Nested Function Calls
function timesTwo($payload) {
return $payload * 2;
}
function addOne($payload) {
return $payload + 1;
}
// outputs 21
echo addOne(
timesTwo(10)
);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Nested Mess
$slug = strtolower(
preg_replace(
'~-+~',
'-',
trim(
preg_replace(
'~[^-w]+~',
'',
preg_replace(
'~[^pLd]+~u',
'-',
'My Awesome Blog Post!'
)
),
'-'
)
)
);
echo $slug;
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Nested Function Calls
function timesTwo($payload) {
return $payload * 2;
}
function addOne($payload) {
return $payload + 1;
}
// outputs 21
echo addOne(
timesTwo(10)
);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Looping Through Stages
$stages = ['timesTwo', 'addOne'];
$payload = 10;
foreach ($stages as $stage) {
$payload = call_user_func($stage, $payload);
}
// outputs 21
echo $payload;
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
–Martin Fowler
“Any fool can write code that a computer can
understand. Good programmers write code that
humans can understand.”
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline
Frank de Jonge

@frankdejonge
Woody Gilk

@shadowhand
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline - Functional
$pipeline = (new Pipeline)
->pipe('timesTwo')
->pipe('addOne');
// Returns 21
$pipeline->process(10);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline - Class Based
$pipeline = (new Pipeline)
->pipe(new TimeTwoStage)
->pipe(new AddOneStage);
// Returns 21
$pipeline->process(10);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Putting it into practice
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
• Create the order

• Calculate the total

• Process the payment

• Subtract coupons from total

• Add appropriate taxes

• Calculate and add shipping costs
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
• Create the order

• Calculate the sub-total

• Subtract coupons from total

• Add appropriate taxes

• Calculate and add shipping costs

• Process the payment
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add coupons
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add coupons
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
// Calculate shipping
// Free shipping on orders $100+
if ($order->order_total < 100) {
$calculator = new ShippingCalculator;
$shipping = $calculator->calculate($order->shipping);
$order->order_total += $shipping;
}
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - testing
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - testing
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add coupons
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
// Add tax
$taxRate = TaxFactory::getRate($order->billing['state']);
$tax = $order->order_total * $taxRate;
$tax = round($tax, 2);
$order->order_total += $tax;
$order->tax = $tax;
// Calculate shipping
// Free shipping on orders $100+
if ($order->order_total < 100) {
$calculator = new ShippingCalculator;
$shipping = $calculator->calculate($order->shipping);
$order->order_total += $shipping;
}
// Process payment
$receipt = $this->paymentGateway->process($order);
$order->confirmation = $receipt->transaction_id;
event(new OrderProcessed($order));
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
class OrderProcessController
{
public function processOrder(Request $request)
{
$order = new Order;
$order->billing = $request->get('billing');
$order->shipping = $request->get('shipping');
$order->products = $request->get('products');
// Calculate sub-total
$productsTotal = 0;
foreach ($request->get('products', []) as $product) {
$productsTotal += ($product['price'] * $product['quantity']);
}
$order->order_total += round($productsTotal, 2);
// Add coupons
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
}
}
Create order
Sub-total
Subtract coupons
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
public function processOrder(Request $request)
{
$order = $this->createOrder($request);
$this->calculateSubTotal($order);
$this->applyCoupon($request, $order);
$this->applyTaxes($order);
$this->calculateShipping($order);
$this->processPayment($order);
$order->save();
return response(null);
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - Testing
protected function applyCoupon(Request $request, Order $order):
void
{
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = new CouponRepository;
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - Testing
protected function applyCoupon(Request $request, Order $order):
void
{
$couponCode = $request->get('coupon');
if ($couponCode) {
$couponRepo = app(CouponRepository::class);
$coupon = $couponRepo->findByCode($couponCode);
$discount = $coupon->isPercentage()
? round($coupon->amount / $order->order_total * 100, 2)
: $coupon->amount;
$order->order_total -= $discount;
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - Testing
public function __construct(CouponRepository $couponRepository)
{
$this->couponRepository = $couponRepository;
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
public function processOrder(Request $request)
{
$order = $this->createOrder($request);
$this->calculateSubTotal($order);
$this->applyCoupon($request, $order);
$this->applyTaxes($order);
$this->calculateShipping($order);
$this->processPayment($order);
$order->save();
return response(null);
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - Testing
public function __construct(
CouponRepository $couponRepository,
ShippingCalculator $shippingCalculator,
PaymentGateway $paymentGateway
) {
$this->couponRepository = $couponRepository;
$this->shippingCalculator = $shippingCalculator;
$this->paymentGateway = $paymentGateway;
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce
public function processOrder(Request $request)
{
$order = $this->createOrder($request);
$this->calculateSubTotal($order);
$this->applyCoupon($request, $order);
$this->applyTaxes($order);
$this->calculateShipping($order);
$this->processPayment($order);
$order->save();
return response(null);
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Stages!
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
eCommerce - Refactored
class OrderProcessController
{
protected $stages = [
CalculateSubTotal::class,
ApplyCoupon::class,
ApplyTaxes::class,
CalculateShipping::class,
ProcessPayment::class,
];
public function processOrder(Request $request)
{
$order = OrderFactory::fromRequest($request);
$pipeline = new LeaguePipelinePipeline;
foreach ($this->stages as $stage) {
$stage = app($stage, ['request' => $request]);
$pipeline->pipe($stage);
}
$pipeline->process($order);
$order->save();
return response(null);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Testing Stages
class OrderProcessTest
{
public function test_sales_tax()
{
$subTotal = 100.00;
$taxRate = 0.06;
$expected = 106.00;
$order = new Order;
$order->order_total = $subTotal;
$order->billing['state'] = 'SC';
$stage = new ApplyTaxes;
$stage($order);
$this->assertEquals($expected, $order->order_total);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Recap
• Pipeline: a series of processes (stages) chained together to
where the output of each is the input of the next.

• Stages create readability, reusability, and testability
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Don't
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Choose wisely
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Encore!
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Fun Stuff - Variable Pipeline
class RelatedData
{
protected $stages = [
LatestActivityPipeline::class,
ListMembershipsStage::class,
WorkflowMembershipsStage::class,
DealsStage::class,
];
public function process()
{
$pipeline = new Pipeline;
foreach ($this->stages as $stage) {
if ($this->stageIsEnabled()) {
$pipeline->pipe(new $stage);
}
}
return $pipeline->process([]);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Fun Stuff - Async Stages
class DealsStage
{
public function __invoke(array $payload)
{
if ($cache = $this->cache->get('deals')) {
$promise = new FulfilledPromise($cache);
} else {
$promise = $this->api->getDeals();
$promise = $promise->then(function ($deals) {
$this->cache->set('deals', $deals);
return $deals;
});
}
$payload['deals'] = $promise;
return $payload;
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Fun Stuff - Async Stages
class RelatedData
{
public function process()
{
$promises = $this->pipeline->process([]);
return GuzzleHttpPromiseunwrap($promises);
}
}
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline - Added Benefits
Processors
• FingersCrossedProcessor
• InterruptibleProcessor
• ProcessorInterface
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
LeaguePipeline - InterruptibleProcessor
$processor = new InterruptibleProcessor(function($payload) {
return $payload < 10;
});
$pipeline = new Pipeline(
$processor,
function ($payload) { return $payload + 2; }, // 7
function ($payload) { return $payload * 10; }, // 70
function ($payload) { return $payload * 10; } // 700
);
// outputs 70
echo $pipeline->process(5);
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Laravel's Pipeline
$stages = [
StageOne::class,
StageTwo::class
];
$result = app(Pipeline::class)
->send($payload)
->through($stages)
->then(function($payload) {
return $payload;
});
Thank you!
Questions / Feedback?
Email: stevenwadejr@gmail.com
Twitter: @stevenwadejr
Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
Suggested Questions
• Is it better to have dynamic stages (e.g. - conditions are run in advance
to determine the steps) or pass all the steps and let the stage contain
it's own condition?

• When should one stage be broken into 2?

More Related Content

What's hot

A (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project FilesA (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project Files
David Wengier
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)
Mark Proctor
 
Watcher
WatcherWatcher
Watcher
Frank Xu
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
Cliff Seal
 
Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017
Christian Aichinger
 
Classic Games Development with Drools
Classic Games Development with DroolsClassic Games Development with Drools
Classic Games Development with Drools
Mark Proctor
 
Speed Things Up with Transients
Speed Things Up with TransientsSpeed Things Up with Transients
Speed Things Up with Transients
Cliff Seal
 
Learning Rule Based Programming using Games @DecisionCamp 2016
Learning Rule Based Programming using Games @DecisionCamp 2016Learning Rule Based Programming using Games @DecisionCamp 2016
Learning Rule Based Programming using Games @DecisionCamp 2016
Mark Proctor
 
What's new in Drools 6 - London JBUG 2013
What's new in Drools 6 - London JBUG 2013What's new in Drools 6 - London JBUG 2013
What's new in Drools 6 - London JBUG 2013
Mark Proctor
 
Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015
Steve Smith
 
Improving code quality with loose coupling
Improving code quality with loose couplingImproving code quality with loose coupling
Improving code quality with loose coupling
Nemanja Ljubinković
 
Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016
Steve Smith
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
Konstantin Kudryashov
 

What's hot (14)

A (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project FilesA (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project Files
 
Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)Drools 6.0 (Red Hat Summit)
Drools 6.0 (Red Hat Summit)
 
Watcher
WatcherWatcher
Watcher
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
 
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
Temporary Cache Assistance (Transients API): WordCamp Phoenix 2014
 
Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017
 
Classic Games Development with Drools
Classic Games Development with DroolsClassic Games Development with Drools
Classic Games Development with Drools
 
Speed Things Up with Transients
Speed Things Up with TransientsSpeed Things Up with Transients
Speed Things Up with Transients
 
Learning Rule Based Programming using Games @DecisionCamp 2016
Learning Rule Based Programming using Games @DecisionCamp 2016Learning Rule Based Programming using Games @DecisionCamp 2016
Learning Rule Based Programming using Games @DecisionCamp 2016
 
What's new in Drools 6 - London JBUG 2013
What's new in Drools 6 - London JBUG 2013What's new in Drools 6 - London JBUG 2013
What's new in Drools 6 - London JBUG 2013
 
Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015
 
Improving code quality with loose coupling
Improving code quality with loose couplingImproving code quality with loose coupling
Improving code quality with loose coupling
 
Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 

Similar to Assemble Your Code in Stages: Leveling Up With Pipelines

You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
andrewnacin
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
Yuya Takeyama
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
Vic Metcalfe
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
10...ish things i learned from programming an e-shop for a year
10...ish things i learned from programming an e-shop for a year10...ish things i learned from programming an e-shop for a year
10...ish things i learned from programming an e-shop for a year
Ines Panker
 
Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019
Thijs Feryn
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
logic321
logic321logic321
logic321
logic321
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
Jace Ju
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
Michelangelo van Dam
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
20 modules i haven't yet talked about
20 modules i haven't yet talked about20 modules i haven't yet talked about
20 modules i haven't yet talked about
Tatsuhiko Miyagawa
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
Fabien Potencier
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
Flavio Poletti
 
PHP API
PHP APIPHP API
PHP API
Jon Meredith
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
Aleix Vergés
 
You Got Async in my PHP!
You Got Async in my PHP!You Got Async in my PHP!
You Got Async in my PHP!
Chris Tankersley
 

Similar to Assemble Your Code in Stages: Leveling Up With Pipelines (20)

You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
10...ish things i learned from programming an e-shop for a year
10...ish things i learned from programming an e-shop for a year10...ish things i learned from programming an e-shop for a year
10...ish things i learned from programming an e-shop for a year
 
Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
logic321
logic321logic321
logic321
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
20 modules i haven't yet talked about
20 modules i haven't yet talked about20 modules i haven't yet talked about
20 modules i haven't yet talked about
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 
PHP API
PHP APIPHP API
PHP API
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
You Got Async in my PHP!
You Got Async in my PHP!You Got Async in my PHP!
You Got Async in my PHP!
 

Recently uploaded

Recycled Concrete Aggregate in Construction Part II
Recycled Concrete Aggregate in Construction Part IIRecycled Concrete Aggregate in Construction Part II
Recycled Concrete Aggregate in Construction Part II
Aditya Rajan Patra
 
ACEP Magazine edition 4th launched on 05.06.2024
ACEP Magazine edition 4th launched on 05.06.2024ACEP Magazine edition 4th launched on 05.06.2024
ACEP Magazine edition 4th launched on 05.06.2024
Rahul
 
Engineering Drawings Lecture Detail Drawings 2014.pdf
Engineering Drawings Lecture Detail Drawings 2014.pdfEngineering Drawings Lecture Detail Drawings 2014.pdf
Engineering Drawings Lecture Detail Drawings 2014.pdf
abbyasa1014
 
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECTCHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
jpsjournal1
 
Casting-Defect-inSlab continuous casting.pdf
Casting-Defect-inSlab continuous casting.pdfCasting-Defect-inSlab continuous casting.pdf
Casting-Defect-inSlab continuous casting.pdf
zubairahmad848137
 
Textile Chemical Processing and Dyeing.pdf
Textile Chemical Processing and Dyeing.pdfTextile Chemical Processing and Dyeing.pdf
Textile Chemical Processing and Dyeing.pdf
NazakatAliKhoso2
 
IEEE Aerospace and Electronic Systems Society as a Graduate Student Member
IEEE Aerospace and Electronic Systems Society as a Graduate Student MemberIEEE Aerospace and Electronic Systems Society as a Graduate Student Member
IEEE Aerospace and Electronic Systems Society as a Graduate Student Member
VICTOR MAESTRE RAMIREZ
 
Recycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part IIIRecycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part III
Aditya Rajan Patra
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
Dr Ramhari Poudyal
 
Manufacturing Process of molasses based distillery ppt.pptx
Manufacturing Process of molasses based distillery ppt.pptxManufacturing Process of molasses based distillery ppt.pptx
Manufacturing Process of molasses based distillery ppt.pptx
Madan Karki
 
官方认证美国密歇根州立大学毕业证学位证书原版一模一样
官方认证美国密歇根州立大学毕业证学位证书原版一模一样官方认证美国密歇根州立大学毕业证学位证书原版一模一样
官方认证美国密歇根州立大学毕业证学位证书原版一模一样
171ticu
 
Computational Engineering IITH Presentation
Computational Engineering IITH PresentationComputational Engineering IITH Presentation
Computational Engineering IITH Presentation
co23btech11018
 
basic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdfbasic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdf
NidhalKahouli2
 
spirit beverages ppt without graphics.pptx
spirit beverages ppt without graphics.pptxspirit beverages ppt without graphics.pptx
spirit beverages ppt without graphics.pptx
Madan Karki
 
Embedded machine learning-based road conditions and driving behavior monitoring
Embedded machine learning-based road conditions and driving behavior monitoringEmbedded machine learning-based road conditions and driving behavior monitoring
Embedded machine learning-based road conditions and driving behavior monitoring
IJECEIAES
 
ISPM 15 Heat Treated Wood Stamps and why your shipping must have one
ISPM 15 Heat Treated Wood Stamps and why your shipping must have oneISPM 15 Heat Treated Wood Stamps and why your shipping must have one
ISPM 15 Heat Treated Wood Stamps and why your shipping must have one
Las Vegas Warehouse
 
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdfBPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
MIGUELANGEL966976
 
Comparative analysis between traditional aquaponics and reconstructed aquapon...
Comparative analysis between traditional aquaponics and reconstructed aquapon...Comparative analysis between traditional aquaponics and reconstructed aquapon...
Comparative analysis between traditional aquaponics and reconstructed aquapon...
bijceesjournal
 
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming PipelinesHarnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Christina Lin
 
Heat Resistant Concrete Presentation ppt
Heat Resistant Concrete Presentation pptHeat Resistant Concrete Presentation ppt
Heat Resistant Concrete Presentation ppt
mamunhossenbd75
 

Recently uploaded (20)

Recycled Concrete Aggregate in Construction Part II
Recycled Concrete Aggregate in Construction Part IIRecycled Concrete Aggregate in Construction Part II
Recycled Concrete Aggregate in Construction Part II
 
ACEP Magazine edition 4th launched on 05.06.2024
ACEP Magazine edition 4th launched on 05.06.2024ACEP Magazine edition 4th launched on 05.06.2024
ACEP Magazine edition 4th launched on 05.06.2024
 
Engineering Drawings Lecture Detail Drawings 2014.pdf
Engineering Drawings Lecture Detail Drawings 2014.pdfEngineering Drawings Lecture Detail Drawings 2014.pdf
Engineering Drawings Lecture Detail Drawings 2014.pdf
 
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECTCHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
CHINA’S GEO-ECONOMIC OUTREACH IN CENTRAL ASIAN COUNTRIES AND FUTURE PROSPECT
 
Casting-Defect-inSlab continuous casting.pdf
Casting-Defect-inSlab continuous casting.pdfCasting-Defect-inSlab continuous casting.pdf
Casting-Defect-inSlab continuous casting.pdf
 
Textile Chemical Processing and Dyeing.pdf
Textile Chemical Processing and Dyeing.pdfTextile Chemical Processing and Dyeing.pdf
Textile Chemical Processing and Dyeing.pdf
 
IEEE Aerospace and Electronic Systems Society as a Graduate Student Member
IEEE Aerospace and Electronic Systems Society as a Graduate Student MemberIEEE Aerospace and Electronic Systems Society as a Graduate Student Member
IEEE Aerospace and Electronic Systems Society as a Graduate Student Member
 
Recycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part IIIRecycled Concrete Aggregate in Construction Part III
Recycled Concrete Aggregate in Construction Part III
 
Literature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptxLiterature Review Basics and Understanding Reference Management.pptx
Literature Review Basics and Understanding Reference Management.pptx
 
Manufacturing Process of molasses based distillery ppt.pptx
Manufacturing Process of molasses based distillery ppt.pptxManufacturing Process of molasses based distillery ppt.pptx
Manufacturing Process of molasses based distillery ppt.pptx
 
官方认证美国密歇根州立大学毕业证学位证书原版一模一样
官方认证美国密歇根州立大学毕业证学位证书原版一模一样官方认证美国密歇根州立大学毕业证学位证书原版一模一样
官方认证美国密歇根州立大学毕业证学位证书原版一模一样
 
Computational Engineering IITH Presentation
Computational Engineering IITH PresentationComputational Engineering IITH Presentation
Computational Engineering IITH Presentation
 
basic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdfbasic-wireline-operations-course-mahmoud-f-radwan.pdf
basic-wireline-operations-course-mahmoud-f-radwan.pdf
 
spirit beverages ppt without graphics.pptx
spirit beverages ppt without graphics.pptxspirit beverages ppt without graphics.pptx
spirit beverages ppt without graphics.pptx
 
Embedded machine learning-based road conditions and driving behavior monitoring
Embedded machine learning-based road conditions and driving behavior monitoringEmbedded machine learning-based road conditions and driving behavior monitoring
Embedded machine learning-based road conditions and driving behavior monitoring
 
ISPM 15 Heat Treated Wood Stamps and why your shipping must have one
ISPM 15 Heat Treated Wood Stamps and why your shipping must have oneISPM 15 Heat Treated Wood Stamps and why your shipping must have one
ISPM 15 Heat Treated Wood Stamps and why your shipping must have one
 
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdfBPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
BPV-GUI-01-Guide-for-ASME-Review-Teams-(General)-10-10-2023.pdf
 
Comparative analysis between traditional aquaponics and reconstructed aquapon...
Comparative analysis between traditional aquaponics and reconstructed aquapon...Comparative analysis between traditional aquaponics and reconstructed aquapon...
Comparative analysis between traditional aquaponics and reconstructed aquapon...
 
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming PipelinesHarnessing WebAssembly for Real-time Stateless Streaming Pipelines
Harnessing WebAssembly for Real-time Stateless Streaming Pipelines
 
Heat Resistant Concrete Presentation ppt
Heat Resistant Concrete Presentation pptHeat Resistant Concrete Presentation ppt
Heat Resistant Concrete Presentation ppt
 

Assemble Your Code in Stages: Leveling Up With Pipelines

  • 1. Assemble Your Code in Stages: Leveling Up With Pipelines
  • 2. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 About me Steven Wade • Husband, father • Founder/Organizer of UpstatePHP Twitter: @stevenwadejr Email: stevenwadejr@gmail.com
  • 3. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem
  • 4. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); $order->save(); return response(null); } }
  • 5. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); $order->save(); return response(null); } }
  • 6. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 7. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 8. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; // Calculate shipping // Free shipping on orders $100+ if ($order->order_total < 100) { $calculator = new ShippingCalculator; $shipping = $calculator->calculate($order->shipping); $order->order_total += $shipping; } // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 9. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Problem class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add coupons $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; // Calculate shipping // Free shipping on orders $100+ if ($order->order_total < 100) { $calculator = new ShippingCalculator; $shipping = $calculator->calculate($order->shipping); $order->order_total += $shipping; } // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 10. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 11. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 12. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Pipelines!*(possibly)
  • 13. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Goals • Understand what a pipeline is, and what stages are • Learn to recognize a pipeline in our code • Refactor code to stages • See how stages make testing easier • Understand when a pipeline is not the appropriate option
  • 14. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 What is a pipeline?
  • 15. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 |
  • 16. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 cat logs.txt | grep "ERROR" | wc -l
  • 17. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 So, what is a pipeline?
  • 18. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Pipeline A series of processes chained together to where the output of each is the input of the next
  • 19. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Stages cat logs.txt | grep "ERROR" | wc -l
  • 20. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Real World Example
  • 21. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Bedtime <?php $bedtime = (new Pipeline) ->pipe(new Bath) ->pipe(new Diaper) ->pipe(new Pajamas) ->pipe(new BrushTeeth) ->pipe(new Book('Catalina Magdalena...')) ->pipe(new Song('Radio Gaga')); $bedtime->process($penny);
  • 22. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 23. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 24. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 25. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 26. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 27. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Gulp gulp.task('css', function(){ return gulp.src('client/templates/*.less') .pipe(less()) .pipe(minifyCSS()) .pipe(gulp.dest('build/css')) });
  • 28. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 29. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 PHP Land
  • 30. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Nested Function Calls function timesTwo($payload) { return $payload * 2; } function addOne($payload) { return $payload + 1; } // outputs 21 echo addOne( timesTwo(10) );
  • 31. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Nested Mess $slug = strtolower( preg_replace( '~-+~', '-', trim( preg_replace( '~[^-w]+~', '', preg_replace( '~[^pLd]+~u', '-', 'My Awesome Blog Post!' ) ), '-' ) ) ); echo $slug;
  • 32. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Nested Function Calls function timesTwo($payload) { return $payload * 2; } function addOne($payload) { return $payload + 1; } // outputs 21 echo addOne( timesTwo(10) );
  • 33. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Looping Through Stages $stages = ['timesTwo', 'addOne']; $payload = 10; foreach ($stages as $stage) { $payload = call_user_func($stage, $payload); } // outputs 21 echo $payload;
  • 34. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 35. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 –Martin Fowler “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
  • 36. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline
  • 37. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline Frank de Jonge
 @frankdejonge Woody Gilk
 @shadowhand
  • 38. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline - Functional $pipeline = (new Pipeline) ->pipe('timesTwo') ->pipe('addOne'); // Returns 21 $pipeline->process(10);
  • 39. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline - Class Based $pipeline = (new Pipeline) ->pipe(new TimeTwoStage) ->pipe(new AddOneStage); // Returns 21 $pipeline->process(10);
  • 40. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Putting it into practice
  • 41. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce • Create the order • Calculate the total • Process the payment • Subtract coupons from total • Add appropriate taxes • Calculate and add shipping costs
  • 42. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce • Create the order • Calculate the sub-total • Subtract coupons from total • Add appropriate taxes • Calculate and add shipping costs • Process the payment
  • 43. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add coupons $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } } }
  • 44. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add coupons $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; // Calculate shipping // Free shipping on orders $100+ if ($order->order_total < 100) { $calculator = new ShippingCalculator; $shipping = $calculator->calculate($order->shipping); $order->order_total += $shipping; } // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 45. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - testing class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; } }
  • 46. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - testing class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; } }
  • 47. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add coupons $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } // Add tax $taxRate = TaxFactory::getRate($order->billing['state']); $tax = $order->order_total * $taxRate; $tax = round($tax, 2); $order->order_total += $tax; $order->tax = $tax; // Calculate shipping // Free shipping on orders $100+ if ($order->order_total < 100) { $calculator = new ShippingCalculator; $shipping = $calculator->calculate($order->shipping); $order->order_total += $shipping; } // Process payment $receipt = $this->paymentGateway->process($order); $order->confirmation = $receipt->transaction_id; event(new OrderProcessed($order)); $order->save(); return response(null); } }
  • 48. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce class OrderProcessController { public function processOrder(Request $request) { $order = new Order; $order->billing = $request->get('billing'); $order->shipping = $request->get('shipping'); $order->products = $request->get('products'); // Calculate sub-total $productsTotal = 0; foreach ($request->get('products', []) as $product) { $productsTotal += ($product['price'] * $product['quantity']); } $order->order_total += round($productsTotal, 2); // Add coupons $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } } } Create order Sub-total Subtract coupons
  • 49. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce public function processOrder(Request $request) { $order = $this->createOrder($request); $this->calculateSubTotal($order); $this->applyCoupon($request, $order); $this->applyTaxes($order); $this->calculateShipping($order); $this->processPayment($order); $order->save(); return response(null); }
  • 50. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - Testing protected function applyCoupon(Request $request, Order $order): void { $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = new CouponRepository; $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } }
  • 51. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - Testing protected function applyCoupon(Request $request, Order $order): void { $couponCode = $request->get('coupon'); if ($couponCode) { $couponRepo = app(CouponRepository::class); $coupon = $couponRepo->findByCode($couponCode); $discount = $coupon->isPercentage() ? round($coupon->amount / $order->order_total * 100, 2) : $coupon->amount; $order->order_total -= $discount; } }
  • 52. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - Testing public function __construct(CouponRepository $couponRepository) { $this->couponRepository = $couponRepository; }
  • 53. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce public function processOrder(Request $request) { $order = $this->createOrder($request); $this->calculateSubTotal($order); $this->applyCoupon($request, $order); $this->applyTaxes($order); $this->calculateShipping($order); $this->processPayment($order); $order->save(); return response(null); }
  • 54. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - Testing public function __construct( CouponRepository $couponRepository, ShippingCalculator $shippingCalculator, PaymentGateway $paymentGateway ) { $this->couponRepository = $couponRepository; $this->shippingCalculator = $shippingCalculator; $this->paymentGateway = $paymentGateway; }
  • 55. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce public function processOrder(Request $request) { $order = $this->createOrder($request); $this->calculateSubTotal($order); $this->applyCoupon($request, $order); $this->applyTaxes($order); $this->calculateShipping($order); $this->processPayment($order); $order->save(); return response(null); }
  • 56. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Stages!
  • 57. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 eCommerce - Refactored class OrderProcessController { protected $stages = [ CalculateSubTotal::class, ApplyCoupon::class, ApplyTaxes::class, CalculateShipping::class, ProcessPayment::class, ]; public function processOrder(Request $request) { $order = OrderFactory::fromRequest($request); $pipeline = new LeaguePipelinePipeline; foreach ($this->stages as $stage) { $stage = app($stage, ['request' => $request]); $pipeline->pipe($stage); } $pipeline->process($order); $order->save(); return response(null); } }
  • 58. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Testing Stages class OrderProcessTest { public function test_sales_tax() { $subTotal = 100.00; $taxRate = 0.06; $expected = 106.00; $order = new Order; $order->order_total = $subTotal; $order->billing['state'] = 'SC'; $stage = new ApplyTaxes; $stage($order); $this->assertEquals($expected, $order->order_total); } }
  • 59. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Recap • Pipeline: a series of processes (stages) chained together to where the output of each is the input of the next. • Stages create readability, reusability, and testability
  • 60. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 61. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853
  • 62. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Don't
  • 63. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Choose wisely
  • 64. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Encore!
  • 65. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Fun Stuff - Variable Pipeline class RelatedData { protected $stages = [ LatestActivityPipeline::class, ListMembershipsStage::class, WorkflowMembershipsStage::class, DealsStage::class, ]; public function process() { $pipeline = new Pipeline; foreach ($this->stages as $stage) { if ($this->stageIsEnabled()) { $pipeline->pipe(new $stage); } } return $pipeline->process([]); } }
  • 66. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Fun Stuff - Async Stages class DealsStage { public function __invoke(array $payload) { if ($cache = $this->cache->get('deals')) { $promise = new FulfilledPromise($cache); } else { $promise = $this->api->getDeals(); $promise = $promise->then(function ($deals) { $this->cache->set('deals', $deals); return $deals; }); } $payload['deals'] = $promise; return $payload; } }
  • 67. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Fun Stuff - Async Stages class RelatedData { public function process() { $promises = $this->pipeline->process([]); return GuzzleHttpPromiseunwrap($promises); } }
  • 68. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline - Added Benefits Processors • FingersCrossedProcessor • InterruptibleProcessor • ProcessorInterface
  • 69. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 LeaguePipeline - InterruptibleProcessor $processor = new InterruptibleProcessor(function($payload) { return $payload < 10; }); $pipeline = new Pipeline( $processor, function ($payload) { return $payload + 2; }, // 7 function ($payload) { return $payload * 10; }, // 70 function ($payload) { return $payload * 10; } // 700 ); // outputs 70 echo $pipeline->process(5);
  • 70. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Laravel's Pipeline $stages = [ StageOne::class, StageTwo::class ]; $result = app(Pipeline::class) ->send($payload) ->through($stages) ->then(function($payload) { return $payload; });
  • 71. Thank you! Questions / Feedback? Email: stevenwadejr@gmail.com Twitter: @stevenwadejr
  • 72. Steven Wade - @stevenwadejrhttps://joind.in/talk/4c853 Suggested Questions • Is it better to have dynamic stages (e.g. - conditions are run in advance to determine the steps) or pass all the steps and let the stage contain it's own condition? • When should one stage be broken into 2?