Software Developer at Vehikl, works with PHP and JavaScript, Meetup organizer
Six million years ago, when dinosaurs roamed the earth and I was in college, lectures were spouting info. Job was to soak up the info. Thankfully now, though, we don't have to soak in information anymore. There's now online resources (e.g. laracasts, laravel news, test driven laravel, vue mastery)
The internet has fundamentally changed education
Changed from passive participants to active facilitators. Benefits and costs; we do have to be more critical of the information we're given. Can't believe everything you read online; not everything on Twitter is good. But you CAN use Twitter to further your education
Phenomenon of the 🔥 tweet (e.g. Hot Tip: On any GitHub repo, hit t to filter for files by name - no more clicking through nested directories. -- Wes Bos)
Fire tweet = information you can trust
Collected a bunch of these tweets, see if I could pull any themes from them
Let's talk about the themes I found
Declarative Programming
Not how something's done (e.g. imperative programming), but what is being done.
If I want a more declarative programming style, think about removing branching logic (but not saying "If statements are bad", "Eradicate If statements"
GIve them a whiff. If they smell good in the code, leave them. Otherwise, maybe see what you can do to change it.
Example shown is a five-layer-nested if block (Cowhead programming)
After example, single layer (no branching logic) (pughead programming)
Scenario
Controller action for updating an article. A number of if-statements, but overall not terribly nested
- Chunk 1: How to find the article
- Chunk 2: How to authorize the update
- Chunk 3: How to get the updated attribute
- Chunk 4: WHAT is being done
In frameworks, 80% of work is handled, letting you do 20% to make the application special
Let's use the framework!
We don't want null values, but you can use $request->intersect([])
to do partial model updates...in Laravel 5.3, and it's no longer there.
Picture of grumpy cat :(
Nowadays, you can use sometimes|required
in a rule. That way, you can say "it doesn't have to be there, but if it is, it has to have a value". Nice.
Next, let's try model route binding. Instead of accepting an ID in the route and in the controller action, typehint the article to get an implicit model binding so we can remove the first chunk that checks if we have an article!
Next, let's figure out the authorization bit. Taylor recommended creating a form request then using the authorize method within there. Now we inject the UpdateArticleRequest in the controller method, now we can remove the validate function AND the authorziation bit.
...but hold on. We're reaching across a bit. Let's create an article policy that handles authorization, then public function update returns user ID equals article's author id. Still WHAT though, so let's refactor to $user->is($article->author)
Now the request authorize is return $this->user()->can('update', $article)
, and it's more declarative
Now the update function in the controller is three lines. Let's just do $updatedAttributes = $request->validated()
...but since we're only using $updatedAttributes
in one place, we can remove that and just do an inline temporary variable.
Reduced a 20-line controller function to...2.
Feature Request
Who is allowed to do it
if ($user->is($article->author)) {
return true;
}
return $user->hasRole(Role::isAdmin()->first());
But with that if-statement, we can probably remove it. Instead of $thing === 'foo' || $thing === 'bar', maybe if (['foo', 'bar'].includes())
We have two groups: admins and users. For an article, we just have one group of folks, so add onto the model and
In Article Policy: $article->editors->contains($user);
Now, articles have hero images
Dealing with file uploads (but send them along to S3). Slidedeck existed before Vapor, so...yeeah
Let's make a new controller (ArticleHeroController)
$hero = $request->file('hero');
$heroUrl = null;
if ($hero) {
$generateHeroName = new GenerateHeroName;
...
}
$article->update(['hero_url' => $heroUrl]);
return ArticleResource::make($article);
First, let's get rid of the if-statement. Taylor recommends calling optional($resource)
; if it's null, it's a no-op, otherwise it'll work
What could be null in our request? $hero. Now we know it'll be something, and we can remove the if-statement!
$hero = optional($request->file('hero'));
We had initialized $heroUrl at the top, but now without the if statement, we can remove that.
You can use set...Attribute to change an existing attribute! For example, setHeroAttribute to modify the underlying hero_url property!
Large chunk goes away. Now updating the article in two lines!
Now...back into testing. In the GenerateHeroName class, if (app()->environment('testing'), return static::$testname? Can only test in production! Yikes.
Testing simple S3 uploads? Use Storage::fake and real-time facades instead!
Storage::fake('s3');
Real-time facades...I don't know how they work, but they're magic
In our model, instead of app\GeneratorHeroName, using real-time facade. Instead of instatiating the generateHeroName, just using facade. Can't really explain it, it's just magic
That's it!