PHP Reddit – Telegram
PHP Reddit
34 subscribers
286 photos
36 videos
24.7K links
Channel to sync with /r/PHP /r/Laravel /r/Symfony. Powered by awesome @r_channels and @reddit2telegram
Download Telegram
you're thinking, this would quickly become unwieldy, with 100 files there. And you're absolutely right - which is why this is a starting point, not the end result. This is just where we jump off from, and as more features are added and boundaries start to define themselves, grouping logic starts to emerge from our code, so we change it. Refactoring this sort of thing is not difficult, particularly if you're using a proper IDE (like Jetbrains). *Cue IDE wars discussion :P*

If this folder started to get too big and hard to see what's going on, I'd likely break it down into Registration and Profile subfolders, but again - all the code related to those features are right there, there's no need to go anywhere else. It also makes it easier to find things that can be hard to locate, such as event listeners.

Let's move on.

# 2. The action pattern

First, like before - a few caveats. I don't hate the action pattern, I've used it myself, and I think it's a great approach, when it makes sense to do so. However, the starting premise regarding the use of the action pattern, is logically incorrect. If you read some articles, they'll talk about how controllers have too much business logic, therefore - use the action pattern. This is paired with the often-misunderstood "single responsibility".

Using an action class to handle what was previously a single controller method, does not resolve the Single Responsibility problem that was seemingly identified. Your action class is still handling http requests, still fetching data from the database, still making state changes to models through leaky abstractions via Eloquent, and still crafting responses. If your business logic was in the right place to begin with, you probably wouldn't reach for the action pattern.

Put another way, your action classes aren't doing what you think they're doing, you're just moving code from one file to another. If you really care about business logic and where it belongs, there's only a few places they can realistically live: commands (no, not console commands - a [command bus](https://www.arnaudlanglade.com/command-bus-design-pattern/)), or service classes.

>I could talk for days about the command bus and how critical it is for well-designed applications, but that's out of scope for this already very lengthy post.

Here's an experiment you can do yourself: are you able to unit test your business logic, without using Laravel classes, models, or providing mocks? No? Then you haven't isolated your business logic. You've just moved code around. Ideally you write your business logic and test that it all works, before wiring it up to the external world, ala Laravel, but I digress.

Secondly, the action pattern results in more code, not less. If you're using controllers, you can share dependencies via the constructor, and have just the dependencies unique to a specific use case injected as part of that specific controller method. If your controllers are massive, there's likely too much going on anyway, and so it's likely that your controllers aren't built to serve well-modelled domains. Eg. Having user registration exist as part of a UserController, rather than having a specific RegistrationController that handles rendering the form, creating the user, confirmation of the account.etc.

I *can* *hear* the ruffled feathers, so let me extend an olive branch...

I am not saying the action pattern is bad, or that you shouldn't use them. They present a very nice, clean way of having code that represents a single feature or use-case in one spot, and works really well in smaller applications. However, don't use them to just move business logic from your controllers to actions. As web developers, we did this 20 years ago, moving business logic from models to controllers. We're having the exact same conversation we had 20 years ago, today, because we collectively still do not understand where business logic ***belongs***.

Think more deeply about where that logic should live, and ask yourself if the action pattern is really serving you in that regard. If you're unsure, DM
me and ask, or comment below! I love helping others and provide insights where I can (mentoring is a passion of mine).

# 3. Repositories and Eloquent

I want to say first of all that I think Eloquent is *brilliant*, and by far one of the best, if not **the** best implementation of the ActiveRecord pattern I've seen. Therefore, my criticisms of Eloquent are not really about Eloquent itself, but more the ActiveRecord pattern that it utilises to make database access and development so damn easy! So whenever I mention Eloquent, it's really just to reference a collective understanding that represents the ActiveRecord pattern.

The main problem is that using Eloquent, well... it's ***too*** easy. It allows you to shoot yourself in the foot, and this becomes a larger problem as your codebase grows. Let me explain.

**Leaky abstractions**

When you work on a codebase long enough (which btw, is a testament to the business for having lasted so long), you begin to see and experience issues with the use of Eloquent. The first is that leaky abstractions make it *very* difficult to replace it ($model->save()), should you need to. This probably sounds theoretical in nature, and for most projects it probably is, but... and I shall quote the Dark Knight here...

>"You either die a hero, or ***live long enough*** to see yourself ***become*** the ***villain***" - Harvey Dent

I love this quote, first because the Dark Knight film was badass, but secondly (and most importantly for this post), it is a perfect encapsulation of the nightmare that Eloquent can become in your codebase. At this point I'd like to reference Shawn McCool's excellent article on the issues around ActiveRecord, a fantastic read if you're interested: [https://shawnmc.cool/active-record-how-we-got-persistence-perfectly-wrong](https://shawnmc.cool/active-record-how-we-got-persistence-perfectly-wrong)

Let me give you a real world example, rather than wax lyrical about "theoretical" problems. 5-6 years ago we needed to support complex search requirements. MySQL just wasn't up to the task, even with well-aggregated (denormalised) data structures. So, we wanted to use ElasticSearch so that we could provide the search features our clients needed. At that time, just one model that we had to replace took 2 months of heavy development, because of leaky abstractions, and expectations on a model that did not conform to an interface (and you can't, in Eloquent, do that nicely, or easily, due to potential name clashes, complex attribute access methods.etc.).

So we ended up replacing the use of Eloquent for that particular feature, migrating the data across.

A leaky abstraction is where you're working with an object, and calling methods or properties that do not belong to that object, such as my example above: $model->save(). That's not **your** code, that's **Laravel** code. Of course, any class we implemented to represent an ElasticSearch object didn't have a save method, so we now had one of two choices, either:

1. Re-implement the save method and any relationship methods it had or
2. Have a better solution in place in case we have to replace it *again*.

We went with the latter, and the resulting system was cleaner, with well-defined responsibilities and boundaries. This was helped ***a lot*** by our use of the repository pattern, because save() was actually encapsulated inside the repository, as were many other Eloquent methods, meaning outside of replacing things like $model->attribute calls, we needed to replace our EloquentSearchRepository with one called ElasticSearchRepository.

This is just one reason why calling relationships and other database access methods on Eloquent models can cause you nightmares down the road: you never know when you're going to need to replace it. Eloquent allows you to reach into totally separate domains and access their data, meaning you have eloquent tendrils everywhere in your codebase. This is even more of a problem than accessing dynamic attributes. But let's stay on repositories for a minute.

Repositories do two things **really**
well:

1. They encapsulate any database access and return the required object and
2. They become a repository for complex queries (huh, maybe that's why they're called that?)

You can also do really cool stuff with them, like wrap them in a decorator for caching, swap persistence strategies at runtime (maybe you have a Redis front, but fallback to the rdbms if redis is down). I've seen criticisms around Repositories which again make me feel like those authors or creators have never worked on a large, complex, evolving application before. They just don't seem like they've seen the front battlelines, they've never been in the trenches, as many seniors have. Ignorance is bliss, as the saying goes (that's not a hateful comment, btw - I'm genuinely jealous).

# Tests alongside code

In almost every PHP project I've seen, and definitely all Laravel projects, all tests live in the tests/ directory, and often mimic the directory structure of your application, where you can find (hopefully) a 1:1 mapping of test file to class file. With 500k lines of code in an application, and 10000 unique test cases, and 40000 assertions, this becomes a real mess. What we do, is the following: our tests live right alongside the class they're testing. And, we go one, manic step further:

* User.php
* User.test.php

The astute amongst you have already noticed the break away from conventions, here: our test file extension. User.test.php is still UserTest as a class, but we call it .test.php so that the file is literally right next to the class it's testing. Else you see silly things like this:

* User.php
* UserRepository.php
* UserService.php
* UserTest.php
* UserRepositoryTest.php

This might seem a small thing, but on large applications it's a real pain, particularly if (in some of our cases), the folder has 30+ files (including tests). It just becomes harder to manually find the test you're looking for (of course, you can always use your IDE shortcut, which is what we mostly do, but sometimes you just gotta eyeball things - **O.O**).

This is supported by our phpunit.xml configuration, as well as some custom bindings/setup to make it all work.

Is it the right approach? Not necessarily, and maybe not for your project. But ever since we started doing this, I do this in all of my projects now. This is true of our feature/acceptance tests as well, where they live alongside the controller or action they're designed to test. This has the added benefit of seeing where there are obvious gaps in our test suite, without needing to do any code coverage analysis, which by the way, can take forever and a day on a large code base!

I'll wrap this up because I have a bunch more I could write and am thinking about doing so on my own YouTube channel (to come soon), but I could honestly write full essays on each of these points, and will likely talk about them in even greater detail in long-form video.

So let me close by reiterating what I've said before. I am not against all these things or their nature. They have their uses, and they work great at various application sizes, it depends on the use-case. What I am against, is evangelical/ideological views that make bold claims that X is bad and should never be used or Y is the best, always use it. I am against the claim that you should "just follow laravel/php/node/whatever conventions". These are arguments that are not rooted in reality, and lack critical thinking, they lack nuance. As a senior software engineer, you need to be thinking critically about every... single... layer. You have to be a slave to nuance, details, or you'll miss things, and you'll make mistakes, mistakes that cost you or your company a fortune.

It is important as developers that we continue to learn and grow, but most importantly, ***be pragmatic***. The suggestions I've made here are not to say "you should replace all conventions or you're a bad developer". Quite the contrary - I've offered alternatives and reasons for doing so, *when it makes sense*, that you do not ***need*** to follow conventions just because someone told you
to.

Every engineering concept has its use-case, its pros and cons, and has gotchas that you need to be mindful of. But as you master your craft, you begin to understand the intent behind these approaches, how best to utilise them so that you can reap the greatest value they provide. Don't do something because someone told you to, do it because you find it interesting and want to continue to grow, and in doing so, become the Engineer you were always meant to be.

If you made it this far, thank you - I value your time and hope I was able to communicate the thoughts that have been running around my head for the last few years. Let me know what you think, and if you disagree, even moreso. I like being challenged and being proven wrong, because it means I learnt something new, and that makes me a better Engineer.

Cheers!

https://redd.it/1p04d6e
@r_php
Open-source eMarket Online Store v1.0 RC-3.5

Greetings, dear colleagues.

This time, I've decided to outline the latest innovations in the eMarket project - https://github.com/musicman3/eMarket.

I'd really appreciate any helpful advice and criticism, as it gives me a better understanding of where to go next. Following previous publications, conclusions have been drawn, and a great deal of work has been done to implement many ideas and approaches.

Currently, the following key libraries have been separated into separate repositories and significantly improved:

Cruder (DB Query Builder) - https://github.com/musicman3/Cruder

R2-D2 (Autorouter) - https://github.com/musicman3/r2-d2

These libraries are now available for study and development, should anyone need them. They form the foundation of eMarket.

Furthermore, jsonRPC has been separately implemented for use as microservices and other purposes. In the future, this will allow for much more efficient handling of external requests. This has proven to be very convenient in practice and will be further developed. The jsonRPC library is also written within the project and is part of it. There was no point in making it a separate library yet, as the code is quite simple.

An automatic updater has already been implemented for the project, which took quite a while. Now you can update directly from the admin panel.

It is also possible to use the platform as a hybrid CMS and online store. This is often necessary for a website that has a denoscriptive section and simultaneously sells products.

Small additions include adding a custom logo and editing language variables from the admin panel.

Best regards.

https://redd.it/1p08xo1
@r_php
PHP Version Update Breaking Stuff

Whenever I bump PHP to the latest version, something on my site breaks, usually some dusty old plugin. I want the speed boost but NOT the stress. How do you guys handle PHP updates without your site falling apart?

https://redd.it/1p0zi91
@r_php
Who's hiring/looking

This is a bi-monthly thread aimed to connect PHP companies and developers who are hiring or looking for a job.

Rules

No recruiters
Don't share any personal info like email addresses or phone numbers in this thread. Contact each other via DM to get in touch
If you're hiring: don't just link to an external website, take the time to describe what you're looking for in the thread.
If you're looking: feel free to share your portfolio, GitHub, … as well. Keep into account the personal information rule, so don't just share your CV and be done with it.

https://redd.it/1p12myc
@r_php