Patterns That Pay Off

60187fe0ab07ea5a46572a3ab05f61dd?s=47 Matt Stauffer
October 19, 2018

Patterns That Pay Off

Given at Laracon 2018 and Laracon AU 2018

60187fe0ab07ea5a46572a3ab05f61dd?s=128

Matt Stauffer

October 19, 2018
Tweet

Transcript

  1. 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. 2.
  3. 3.

    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
  4. 6.

    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
  5. 7.

    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
  6. 8.

    If all you have is a hammer, everything looks like

    a nail. Preventative vs. Reactive
  7. 9.

    If all you have is a hammer, everything looks like

    a nail. command bus command Preventative vs. Reactive
  8. 21.

    • You think you can predict the future • You

    can’t predict the future • Source of process anti-patterns No precogs
  9. 22.

    $ • 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
  10. 24.

    • Establish and enforce standards • Code style • Code

    organization • Trusted packages • Version control naming and branching strategies • Pull request Strategies • etc. Codebase Consistency
  11. 25.

    I don’t want to be able to tell who wrote

    the code just from looking at it.
  12. 26.

    $ • 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
  13. 28.

    • Shell scripts for common tasks • Examples: • ./bin/init.sh

    • ./bin/update.sh • ./bin/precommit.sh • ./bin/deploy.sh Bin scripts
  14. 29.

    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
  15. 30.

    $ • 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
  16. 31.
  17. 32.

    • 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
  18. 33.

    $ • 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
  19. 34.

    • Review your own code diff before asking for review

    • Less wasted Senior dev review BONUS TIP: Six eyes!
  20. 36.

    • 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
  21. 37.

    $ • 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
  22. 39.

    • 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
  23. 40.

    $ • 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
  24. 43.

    • 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
  25. 44.

    $ • 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
  26. 46.

    • 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
  27. 47.

    $ • 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
  28. 49.

    • 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
  29. 50.

    $ • 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
  30. 52.

    • 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
  31. 53.

    $ • 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
  32. 56.

    • 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
  33. 57.

    $ • 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
  34. 59.

    • 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
  35. 60.

    $ • Shorter methods • “Separation of Concerns” • Easier

    and clearer and more obvious testing • You get to say “POPO” more Service Classes: the payoff
  36. 62.

    • Much app complexity comes from parsing HTTP requests •

    See Laravel’s “Form Requests” for inspiration • More possibilities… Custom Requests
  37. 63.

    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. }
  38. 64.

    $ • Smaller controllers • Easier testing • Separate repetitive

    input logic (e.g. preparing data) Custom Requests: the payoff
  39. 66.

    • 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
  40. 67.

    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));
  41. 68.

    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));
  42. 69.

    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);
  43. 70.

    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);
  44. 71.

    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'])
  45. 72.

    $ • Slimmer controllers • Clearer grouping and composition of

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