• 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
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
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
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
“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
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
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
• 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
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
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
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
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
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
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
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
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
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
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
function prepared() { // Do stuff here with the data } } // In controller: public function store(SignUpRequest $request) { $data = $request->prepared(); // ... etc. }
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
$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));
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);
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);