Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

The correct posture towards patterns PART I

Slide 5

Slide 5 text

Preventative vs. Reactive

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Underlying: YAGNI-KISS-etc.

Slide 11

Slide 11 text

Page Title

Slide 12

Slide 12 text

Page Title

Slide 13

Slide 13 text

Page Title

Slide 14

Slide 14 text

Page Title

Slide 15

Slide 15 text

Write code that is easy to delete.

Slide 16

Slide 16 text

Pay off > Patterns

Slide 17

Slide 17 text

Matt’s Patterns PART II

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Process patterns 1

Slide 20

Slide 20 text

No precogs

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Codebase Consistency

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Bin scripts ./bin/

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Four Eyes

Slide 32

Slide 32 text

• 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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Document the weird // Ignore

Slide 36

Slide 36 text

• 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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Lower-case agile

Slide 39

Slide 39 text

• 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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Architecture patterns 2

Slide 42

Slide 42 text

Monolith first

Slide 43

Slide 43 text

• 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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Seeds, not Dumps

Slide 46

Slide 46 text

• 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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Test to save your job

Slide 49

Slide 49 text

• 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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Scalable tasks

Slide 52

Slide 52 text

• 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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

(Re)factoring patterns 3

Slide 55

Slide 55 text

Seed each test

Slide 56

Slide 56 text

• 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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Service Classes

Slide 59

Slide 59 text

• 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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Custom Requests

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

View Data Composition

Slide 66

Slide 66 text

• 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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Conclusions PART III

Slide 74

Slide 74 text

Not everyone needs a root canal.

Slide 75

Slide 75 text

mattstauffer.com/ talks/patterns ❤