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

Patterns That Pay Off

Matt Stauffer
October 19, 2018

Patterns That Pay Off

Given at Laracon 2018 and Laracon AU 2018

Matt Stauffer

October 19, 2018
Tweet

More Decks by Matt Stauffer

Other Decks in Technology

Transcript

  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

    View full-size slide

  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

    View full-size slide

  3. The correct posture
    towards patterns
    PART I

    View full-size slide

  4. Preventative
    vs.
    Reactive

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. Underlying:
    YAGNI-KISS-etc.

    View full-size slide

  10. Write code that is
    easy to delete.

    View full-size slide

  11. Pay off > Patterns

    View full-size slide

  12. Matt’s Patterns
    PART II

    View full-size slide

  13. Three types of pattern
    1. Process
    2. Architecture
    3. (Re)factoring

    View full-size slide

  14. Process patterns
    1

    View full-size slide

  15. • You think you can predict the future
    • You can’t predict the future
    • Source of process anti-patterns
    No precogs

    View full-size slide

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

    View full-size slide

  17. Codebase Consistency

    View full-size slide

  18. • Establish and enforce standards
    • Code style
    • Code organization
    • Trusted packages
    • Version control naming and branching strategies
    • Pull request Strategies
    • etc.
    Codebase Consistency

    View full-size slide

  19. I don’t want to be able to tell
    who wrote the code just from
    looking at it.

    View full-size slide

  20. $
    • 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

    View full-size slide

  21. Bin scripts
    ./bin/

    View full-size slide

  22. • Shell scripts for common tasks
    • Examples:
    • ./bin/init.sh
    • ./bin/update.sh
    • ./bin/precommit.sh
    • ./bin/deploy.sh
    Bin scripts

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. • Review your own code diff before asking for review
    • Less wasted Senior dev review
    BONUS TIP: Six eyes!

    View full-size slide

  28. Document the weird
    // Ignore

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. Lower-case agile

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. Architecture patterns
    2

    View full-size slide

  35. Monolith first

    View full-size slide

  36. • 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

    View full-size slide

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

    View full-size slide

  38. Seeds, not Dumps

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  41. Test to save your job

    View full-size slide

  42. • 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

    View full-size slide

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

    View full-size slide

  44. Scalable tasks

    View full-size slide

  45. • 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

    View full-size slide

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

    View full-size slide

  47. (Re)factoring patterns
    3

    View full-size slide

  48. Seed each test

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  51. Service Classes

    View full-size slide

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

    View full-size slide

  53. $
    • Shorter methods
    • “Separation of Concerns”
    • Easier and clearer and more obvious testing
    • You get to say “POPO” more
    Service Classes: the payoff

    View full-size slide

  54. Custom Requests

    View full-size slide

  55. • Much app complexity comes from parsing HTTP
    requests
    • See Laravel’s “Form Requests” for inspiration
    • More possibilities…
    Custom Requests

    View full-size slide

  56. 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.
    }

    View full-size slide

  57. $
    • Smaller controllers
    • Easier testing
    • Separate repetitive input logic (e.g. preparing data)
    Custom Requests: the payoff

    View full-size slide

  58. View Data Composition

    View full-size slide

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

    View full-size slide

  60. 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));

    View full-size slide

  61. 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));

    View full-size slide

  62. 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);

    View full-size slide

  63. 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);

    View full-size slide

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

    View full-size slide

  65. $
    • Slimmer controllers
    • Clearer grouping and composition of data and its
    sources
    • Easier testing
    • Fun words like “Responsable” and “Htmlable”
    View Data Composition: the payoff

    View full-size slide

  66. Conclusions
    PART III

    View full-size slide

  67. Not everyone needs
    a root canal.

    View full-size slide

  68. mattstauffer.com/
    talks/patterns

    View full-size slide