Back Button PHP

Whip Monstrous Code Into Shape

You did your best, but somehow that User object, over time, morphed into a monstrous God object. And your controllers started out nice and clean, but now... not so much.

We've all been there. In this series, we'll review a number of ideas for whipping convoluted code into shape.

20 episodes
3:40:31 hrs
Start Series
    1. Run Time 19:39 Free

      A form object manages a single form in your application. It handles validation, potentially authorization, and finally - if you wish - persistence. In this lesson, we'll write an implementation from scratch, and then switch over to reviewing Laravel's form request classes and how they fit into the mix.

      View the source for this lesson on GitHub.

    2. Run Time 13:11

      A use case is nothing more than a description of how a user should interact with a particular part of your system. Traditionally, this description may be written on something as simple as an index card. However, what if we applied this approach to the code, itself? What might that look like?

    3. If it makes sense for your application, you might consider leveraging domain events and listeners to construct a complex set of functionality.

    4. Any developer who has worked on the same project for a year or more will be well aware of the fact that, if you're not careful, your User class can quickly turn into a monstrous God object. In the next few videos, one tip at a time, we'll review techniques you might implement to clean things up.

      In this first example, we'll recognize related methods, and extract them to a dedicated object - which we then pass through to from our main User class.

    5. Let's review the next option you have, when cleaning up big, bad God objects: extracting traits. While some developers have knee-jerk reactions to the concept of a trait that will never be used elsewhere, I find it to be a clean and convenient solution. It's akin to cleaning up your room, by placing all the socks in one drawer, and the shirts in another. Admittedly, you didn't design a new closet space, but there's no denying that the room is now cleaner as a result.

    6. Extracting value objects, when appropriate, can be a useful technique for cleaning up messy classes. Use a simple metric: if you find multiple pieces of behavior that surround a single primitive or value, consider a value object. Please note that developers often have a tendency to "value object all the things," so be careful. Refactor toward value objects, rather than adopting them by default for every possible value.

      View the source for this lesson on GitHub.

    7. Run Time 16:32

      If you find that your controllers are performing too much authorization logic, you might consider policy objects. This allows you to assign a name to important (possibly complex) authorization logic that can reused anywhere. Or, in other words, if you make five different verifications to determine if a member may be added to a team, why not instead reference an AddTeamMemberPolicy object? Let's review two different ways to accomplish this, first using a simple class, and then leveraging Laravel's built-in policy functionality.

      Review the source for this lesson on GitHub.

    8. What do you do in the situations where a particular task consists of a dozen different unique steps? Well we've already reviewed a number of options in this series, including use-cases and events; however, another perfectly acceptable route is to extract each step into its own class, and then filter through an array of these bite-sized classes and trigger them. I'll show you how.

    9. Tutorials often illustrate the simplest possible path through your codebase to demonstrate a particular concept. But the truth is that, in real life, things can quickly become quite a bit more complicated. For example, imagine that your website allows users to sign up for subscriptions. The only problem is that, based upon the form request data, you'll need to execute this process in multiple ways. Sounds like you're going to have lots of conditionals in your controller, right? Well, maybe there's another option: strategies.

    10. Run Time 15:29

      You'll frequently find yourself in the position of needing to normalize a particular value. Sure, the value might be in the proper format from the start; but it could also be in the form of a function that you need to trigger. Or maybe, based upon various business rules, you need to first modify the value before continuing on. Well, if you're not careful, your code can get pretty messy, pretty fast.

      One option you might consider is extracting all of the normalizing-specific code into either its own method, or a different class entirely. In this episode, we'll cycle through a number of refactors that you might consider.

    11. Run Time 11:05

      When you find yourself repeating the same view logic over and over, it might be time to extract that code into a reusable method. At first, developers typically reach for the model. However, you may quickly decide that you'd prefer a more dedicated class for this sorts of logic. In such cases, consider creating view presenters - or as some refer to them: view models.

      View the source code for this lesson on GitHub.

    12. As a general guideline, when you find yourself wanting to create a method with four or more parameters, that might be an indication that there's a missing class. You may want to refactor. As always, rules are meant to be broken, but, nonetheless, train yourself to be suspicious of such methods.

    13. Run Time 9:04

      The next option you have when cleaning up monstrous code is opting for decorators. This allows you to stack on behavior to an existing class dynamically. I'll show you how; it's easy!

    14. Fluent interfaces often get a bad rap, but the truth is that there are countless scenarios where you may consider leveraging them. In this episode, we'll review the basic definition and makeup for a fluent API, and will then move on discussing a handful of real-life examples in the wild.

    15. Run Time 18:18

      Let's put some of the skills we've learned in this series to the test. We'll take an existing real-life class, and refactor it using the techniques we reviewed in episode eight of this series.

      View a sampling of the source from this lesson on GitHub.

    16. In this monstrous code episode, we'll review one technique to help keep your controllers in check. Have you ever created a resourceful controller, but found yourself, over time, adding more and more actions to it? It starts to get pretty bloated, right? Well what if, instead, you took that non-resourceful action and extracted it its a new controller? What might that look like?

    17. Most tutorials demonstrate the simplest possible Eloquent queries. You know, the one where you do Post::all() and move on. But, in reality, you're often writing significantly more complex queries. So what do we do, when they get too large and gross to keep in the controller? Well, we could extract to the model, we could create a repository, or we could make a single-use query class. Let me show you how; it's easy!

      View the demo source for this episode on GitHub.

    18. So you've begun to wrangle your monstrous User God object into place? Great - but now what about your views? Developers sometimes have a tendency to ignore the structure and cleanliness of their templates. Try not to do this. Give the same respect to each template, as you would to any PHP class. In this episode, we'll review a handful of techniques for refactoring your views.

    19. Have you ever found yourself in the situation where you're constantly checking, within your views, to see if a user is signed in before proceeding? "If the user is signed in, and if they are subscribed, then...." It gets annoying, doesn't it? Hmm - what alternatives do we have here?

    20. Imagine that you perform an API request to fetch a bit of JSON. That response will become an array of objects, once decoded. Too often, though, I see developers littering their views or creating helper functions, all to add a bit of behavior or formatting to how the data is rendered. There's no need for this. Instead, you might consider wrapping each item within a simple POPO, and then add your behavior and formatting to this class alone.