Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Patterns That Pay Off

Patterns That Pay Off

Given at Laracon 2018 and Laracon AU 2018

Matt Stauffer

October 19, 2018

More Decks by Matt Stauffer

Other Decks in Technology


  1. PRESENTED BY Patterns That Pay Off Design, behavior, and organizational

    patterns that will make a real impact on your company and codebase Your Friend Matt @stauffermatt
  2. pattern 1. a regular and intelligible form or sequence discernible

    in certain actions or situations 2. a model or design used as a guide in needlework and other crafts. noun
  3. Do this on every app no matter what; e.g. “floss

    every day,” “avoid N+1 queries,” “avoid env() calls in non-config code” Preventative patterns Preventative vs. Reactive
  4. Feel/see the pain then choose the fix; e.g. “root canal

    to treat cracked tooth,” “microservice to isolate slow adapter infrastructure,” “factory to normalize multiple exchangeable implementations” Reactive patterns Preventative vs. Reactive
  5. If all you have is a hammer, everything looks like

    a nail. Preventative vs. Reactive
  6. If all you have is a hammer, everything looks like

    a nail. command bus command Preventative vs. Reactive
  7. • You think you can predict the future • You

    can’t predict the future • Source of process anti-patterns No precogs
  8. $ • When you try to predict the future, you:

    • Commit to unrealistic timelines, leading to unhappy clients and unhappy devs • Over-architect to try to reduce Cost of Change • Become rigid, and can’t flex with new requirements • Instead, feel free to do the best work you can with what’s in front of you No precogs: the payoff
  9. • Establish and enforce standards • Code style • Code

    organization • Trusted packages • Version control naming and branching strategies • Pull request Strategies • etc. Codebase Consistency
  10. I don’t want to be able to tell who wrote

    the code just from looking at it.
  11. $ • Easier onboarding and less cognitive load when entering

    a new codebase • Good patterns become ingrained easily into company culture and new-dev onboarding • Devs spend brainpower on stuff that matters Codebase Consistency: the payoff
  12. • Shell scripts for common tasks • Examples: • ./bin/init.sh

    • ./bin/update.sh • ./bin/precommit.sh • ./bin/deploy.sh Bin scripts
  13. Bin Scripts #!/bin/bash # Sample bin/init.sh composer install cp .env.example

    .env php artisan key:generate php artisan migrate —seed npm install npm run dev #!/bin/bash # Sample bin/update.sh composer install php artisan migrate npm install npm run dev
  14. $ • Easier onboarding and less cognitive load when entering

    a new codebase • Less time wasted on “it works for me” or “did you remember to _____” • More likelihood developers will discover the steps for onboarding (devs don’t read docs ) Bin scripts: the payoff
  15. • No code can get merged to production without two

    sets of eyes on it • One developer + one code reviewer • (OR) Two pair programmers Four Eyes * If any team members have more or less than two eyes, this number can be modified
  16. $ • Avoid the negative consequences of hyper focus •

    “Reviewing brain” is often different from “writing brain” • Any two developers bring different perspective, broadening the team’s capabilities • Share load of responsibility for all new code introduced Four Eyes: the payoff
  17. • Review your own code diff before asking for review

    • Less wasted Senior dev review BONUS TIP: Six eyes!
  18. • Self-documenting code # • … some code (e.g. complex

    database queries) just takes time to grok what it does • … more code takes time to grok why it does what it does • Avoid // Show the resource • Aim for // Exclude the connections that match both user ID *and* service ID Document the weird
  19. $ • Faster comprehension of complex code • Less wasted

    lines/visual debt on useless documentation • Less useless docs = people read docs more • Records business priorities Document the weird: the payoff
  20. • Agile Manifesto != The Agile Industrial Complex • “Agile”

    is often waterfall, rebranded • Return to agility • “Gee, Spider-Man super is agile!” instead of “I’m a Certified Agile Scrum-Master 3000” • Stay light, respond quickly, adjust often • Militia vs. large army Lower-case agile
  21. $ • Agile promises • React quickly to new information/stimuli

    • Deliver functional iterations early and often • Flexibility around different workers & different projects • Without Agile costs • No one saying “I can’t pull that because it will mess up the burndown chart” • Focus on delivering great software, not fitting a system Lower-case agile: the payoff
  22. • You’ve heard of API-first: design the API, consume it

    with both JavaScript and mobile • You’ve heard of microservices: split your app into a million pieces so each is independent • Consider monolith first • API-first and microservices have their place • …but aren’t free • …especially on small teams Monolith first
  23. $ • Avoid API-first/microservice-first costs: • More complicated and duplicated

    validation • More complicated and error-prone synchronization of testing data and expectations • More complicated branching and deploy strategies • Higher up-front development costs • Reduced flexibility Monolith first: the payoff
  24. • Don’t rely on dumps of production data for new

    devs or testing • Build robust, randomized seeders • Check features under development on randomized seeds, not the narrower set of data-we-currently-have- in-production • Keep production data in production • Pro tip: reference production data to help you improve seeds Seeds, not dumps
  25. $ • Easier CI/CD • Easier testing • Easier onboarding

    new users • Easier bug fixing • Less scared to make changes locally • Reduces fragility
 (less likely to only work if the data is a certain way) Seeds, not dumps: the payoff
  26. • The best place to start your tests is by

    asking yourself: “what part of this app, if broken, would make me worried for my job?” • …“what’s most likely to break” • …“what do I have the least control over” • …“what are we about to refactor” • …“what would make my clients stress out” • …“what would make me stress out” Test to save your job
  27. $ • You get to keep your job • Testing

    because it’s providing immediate value,
 not because someone told you you should • Most important tests first • You get to keep your job Test to save your job: the payoff
  28. • Reentrance: If a task is interrupted, it can be

    restarted and completed successfully • Idempotence: A task can be called multiple times,
 without changing the side effects • Concurrence: More than one of a task can be run
 at the same time • Sequence Independence: The order of the tasks
 doesn’t matter Scalable tasks
  29. $ • Easy multi-worker spinup • No fears/stress about re-running

    jobs or crons • Reduces fragility
 —less centering everything around one server being in one particular state Scalable tasks: the payoff
  30. • Once you start seeding, it’s tempting to seed everything

    up front, once, for all your tests • It’s OK to seed some broad data up front—“company”, “user”—but uniquely seed the data under test in the test setup itself • Factory states and stories can be helpful here Seed each test
  31. $ • No magic numbers • No need to flush

    work affected by previous tests • No “it works when we run this other test before but not when we don’t” • Data and tests on that data are in the same file, so they’re easier to connect and reason about Seed each test: the payoff
  32. • Catchall for “POPO (Plain Old PHP Object)” that does

    stuff without being specifically tied to a design pattern or framework structure • Get creative with your naming (e.g. RetrieveMoviePoster) • Consider __invoke():
 RetrieveMoviePoster() Service Classes
  33. $ • Shorter methods • “Separation of Concerns” • Easier

    and clearer and more obvious testing • You get to say “POPO” more Service Classes: the payoff
  34. • Much app complexity comes from parsing HTTP requests •

    See Laravel’s “Form Requests” for inspiration • More possibilities… Custom Requests
  35. View Data Composition: Presenters class SignUpRequest extends Request { public

    function prepared() { // Do stuff here with the data } } // In controller: public function store(SignUpRequest $request) { $data = $request->prepared(); // ... etc. }
  36. $ • Smaller controllers • Easier testing • Separate repetitive

    input logic (e.g. preparing data) Custom Requests: the payoff
  37. • Many oversized controllers/controller methods are because of the cost

    of organizing data for a specific view • Presenter: Layer on top of other thing, often model, to give it more powers in views (like a decorator for views) • View model: View POPO for organizational purposes • Responsable: interface in Laravel for a PHP object of any class that can be converted to a response • View components: idea/package for Vue-component- style view data composition View Data Composition
  38. View Data Composition: Presenters class PostPresenter { public function __construct(Post

    $post) { $this->post = $post; } public function presentPublishedAt() { return $this->published_at->format('M j, Y'); } // Use custom methods, *or* use a presenter package to get magic // Eloquent-style accessors } // In controller: return view('posts.show')->with('post', new PostPresenter($post));
  39. View Data Composition: View Models class DashboardViewModel { public function

    __construct(User $user) { $this->user = $user; } public function topTasks() { $overdue = $this->overdueTasks(); return array_merge($overdue, $this->fillTasksDueSoon(count($overdue))); } public function progressChart() { return [ 'percentage_complete' => $this->progressPercentageComplete(), 'date_markers' => $this->dateMarkers(), ]; } ... // In use: return view('dashboard')->with('vm', new DashboardViewModel($user));
  40. View Data Composition: Responsables class DashboardViewResponse implements Responsable { //...

    other prep the same as before in the view model public function prepareData() { return [ 'tasks' => $this->tasks, // etc. ]; } public function toResponse() { $data = $this->prepareData(); return response()->view('dashboard', $data); } // In use (in the controller): return new DashboardViewResponse($user);
  41. View Data Composition: Responsables class DashboardViewResponse implements Responsable { //...

    other prep the same as before in the view model public function prepareData() { return [ 'tasks' => $this->tasks, // etc. ]; } public function toResponse() { $data = $this->prepareData(); if (request()->ajax()) { return response()->json($data); } return view('dashboard', $data); } // In use (in the controller): return new DashboardViewResponse($user);
  42. View Data Composition: View Components class NavigationComponent implements Htmlable {

    public function __construct(Request $request, $backgroundColor) { $this->request = $request; $this->backgroundColor = $backgroundColor; } public function toHtml() { return view('components.navigation', [ 'activeUrl' => $this->request->url(), 'backgroundColor' => $this->backgroundColor, ]); } // In use: @render('navigationComponent', ['backgroundColor' => 'black'])
  43. $ • Slimmer controllers • Clearer grouping and composition of

    data and its sources • Easier testing • Fun words like “Responsable” and “Htmlable” View Data Composition: the payoff