SlideShare ist ein Scribd-Unternehmen logo
1 von 72
Downloaden Sie, um offline zu lesen
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?

Weitere ähnliche Inhalte

Was ist angesagt?

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 FilesDavid 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
 
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 2019David 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 2014Cliff Seal
 
Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Parallel Computing With Dask - PyDays 2017
Parallel Computing With Dask - PyDays 2017Christian Aichinger
 
Classic Games Development with Drools
Classic Games Development with DroolsClassic Games Development with Drools
Classic Games Development with DroolsMark Proctor
 
Speed Things Up with Transients
Speed Things Up with TransientsSpeed Things Up with Transients
Speed Things Up with TransientsCliff 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 2016Mark 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 2013Mark Proctor
 
Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015Understanding Git - GOTO London 2015
Understanding Git - GOTO London 2015Steve Smith
 
Improving code quality with loose coupling
Improving code quality with loose couplingImproving code quality with loose coupling
Improving code quality with loose couplingNemanja Ljubinković
 
Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016Understanding git: Voxxed Vienna 2016
Understanding git: Voxxed Vienna 2016Steve 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 2015Konstantin Kudryashov
 

Was ist angesagt? (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
 

Ähnlich wie 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
 
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
 
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 yearInes Panker
 
Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019Developing cacheable backend applications - Appdevcon 2019
Developing cacheable backend applications - Appdevcon 2019Thijs Feryn
 
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
 
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
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
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 CracowKacper 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 aboutTatsuhiko Miyagawa
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityRyan 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 DDDAleix Vergés
 

Ähnlich wie 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!
 

Kürzlich hochgeladen

VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130Suhani Kapoor
 
UNIT-V FMM.HYDRAULIC TURBINE - Construction and working
UNIT-V FMM.HYDRAULIC TURBINE - Construction and workingUNIT-V FMM.HYDRAULIC TURBINE - Construction and working
UNIT-V FMM.HYDRAULIC TURBINE - Construction and workingrknatarajan
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...Soham Mondal
 
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Call Girls in Nagpur High Profile
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).pptssuser5c9d4b1
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCall Girls in Nagpur High Profile
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Christo Ananth
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performancesivaprakash250
 
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls in Nagpur High Profile
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINESIVASHANKAR N
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSISrknatarajan
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Dr.Costas Sachpazis
 
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete RecordCCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete RecordAsst.prof M.Gokilavani
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxpranjaldaimarysona
 
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...Call Girls in Nagpur High Profile
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
result management system report for college project
result management system report for college projectresult management system report for college project
result management system report for college projectTonystark477637
 

Kürzlich hochgeladen (20)

VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
 
UNIT-V FMM.HYDRAULIC TURBINE - Construction and working
UNIT-V FMM.HYDRAULIC TURBINE - Construction and workingUNIT-V FMM.HYDRAULIC TURBINE - Construction and working
UNIT-V FMM.HYDRAULIC TURBINE - Construction and working
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
 
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
 
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
Call Girls in Nagpur Suman Call 7001035870 Meet With Nagpur Escorts
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
247267395-1-Symmetric-and-distributed-shared-memory-architectures-ppt (1).ppt
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performance
 
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service NashikCall Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
Call Girls Service Nashik Vaishnavi 7001305949 Independent Escort Service Nashik
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
 
UNIT-III FMM. DIMENSIONAL ANALYSIS
UNIT-III FMM.        DIMENSIONAL ANALYSISUNIT-III FMM.        DIMENSIONAL ANALYSIS
UNIT-III FMM. DIMENSIONAL ANALYSIS
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
 
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete RecordCCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptx
 
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
result management system report for college project
result management system report for college projectresult management system report for college project
result management system report for college project
 

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?