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 Slide

  2. View Slide

  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

    View Slide

  4. The correct posture
    towards patterns
    PART I

    View Slide

  5. Preventative
    vs.
    Reactive

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  10. Underlying:
    YAGNI-KISS-etc.

    View Slide

  11. Page Title

    View Slide

  12. Page Title

    View Slide

  13. Page Title

    View Slide

  14. Page Title

    View Slide

  15. Write code that is
    easy to delete.

    View Slide

  16. Pay off > Patterns

    View Slide

  17. Matt’s Patterns
    PART II

    View Slide

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

    View Slide

  19. Process patterns
    1

    View Slide

  20. No precogs

    View Slide

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

    View Slide

  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

    View Slide

  23. Codebase Consistency

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  27. Bin scripts
    ./bin/

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  31. Four Eyes

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  35. Document the weird
    // Ignore

    View Slide

  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

    View Slide

  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

    View Slide

  38. Lower-case agile

    View Slide

  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

    View Slide

  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

    View Slide

  41. Architecture patterns
    2

    View Slide

  42. Monolith first

    View Slide

  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

    View Slide

  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

    View Slide

  45. Seeds, not Dumps

    View Slide

  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

    View Slide

  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

    View Slide

  48. Test to save your job

    View Slide

  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

    View Slide

  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

    View Slide

  51. Scalable tasks

    View Slide

  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

    View Slide

  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

    View Slide

  54. (Re)factoring patterns
    3

    View Slide

  55. Seed each test

    View Slide

  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

    View Slide

  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

    View Slide

  58. Service Classes

    View Slide

  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

    View Slide

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

    View Slide

  61. Custom Requests

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. View Data Composition

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  73. Conclusions
    PART III

    View Slide

  74. Not everyone needs
    a root canal.

    View Slide

  75. mattstauffer.com/
    talks/patterns

    View Slide