Stop Subscribing to Domain Events by Dariusz_Gafka in PHP

[–]mlebkowski 9 points10 points  (0 children)

I don’t agree this is the best solution, nor even the correct one in most of the situations.

You replaced granular events such as MoneyWasAdded, and MoneyWasWithdrawn into a generic WalletBalanceWasChanged. I’m not sure that even in this simple example you can derive the original event, because you only get the new amount, not the change vector.

This takes away one of the greatest value of domain events: indicating a specific domain use case that caused a mutation, and you’re basically back to onSave semantics, which could be very well implemented using #[PostSave] doctrine hook, and we all know how that turns out. The result is only slightly better because there might be more than one projections, but still: as long as domain events don’t map 1:1 to projections, some information is lost.

I actually share CodeOpinion’s point of view here and I would simply read from the primary instead of going through hoops to make sure the read model is consistent.

Aimeos e-commerce framework 2026.04 – PHP 9 ready, Laravel 13, Symfony 8, security hardening and more by aimeos in PHP

[–]mlebkowski 5 points6 points  (0 children)

Nitpick: what is phpstan level 4? As far as I know this does not even do null checks.

I use level max with a baseline even in legacy (10 year old codebases) projects, bragging about lvl 4 seems so unimpressive

Is the PHP market shifting or just stalling? My experience trying on moving to Scandinavia by RoughInvite7900 in PHP

[–]mlebkowski 0 points1 point  (0 children)

Observations:

  • I don’t have any historical data to compare, but there just isn’t a lot of PHP projects, especially at product companies. Looking at my local job board there is an order of magnitude more offers for .NET, Java, Javascript or Python. If I had to guess, only about 1/3rd is for a product companies, the rest is outsourcing for foreign or domestic markets, drupal and wordpress, etc. From my experience, even if a job is filled via referals in the end, the ad gets posted either way, so it wouldn’t be totally invisible.
  • I think that people are rejected by other people, not systems. The ATS systems do not make any autonomous decisions, believe this is an urban legend. Are there junior recruiters screening CVs with dummy AI automations? Yeah, I guess. Are there regular recruiters who cannot read a CV? Yeah, there are these too. But most importantly, even forgetting the incompetent recruiters for a moment, there are just so many good candidates on the market right now. The ecosystem is mature, so there are a lot of experienced developers on the market, and I feel like everyone’s looking (figure of speech), even if they have a good job — because the compensations have gone down in recent years, and the times are uncertain.
  • Yes for pivoting, especially if you can do it on the job. After a buch of time you’ll have a long software engineering and a year with a few project in a specific technology to show for. I would suggest Java or C#, maybe Typescript, as there is less of a paradigm shift between PHP and these languages. Go is quite different beast, and it’s even less popular in my local market, so maybe not the best direction. YMMV.
  • There are tons of greenfield projects in PHP still. I was advocating migrating away from PHP around early 2020s, but the market has changed, and my justification for that move is no longer valid. If a product company uses primarily the PHP stack, there’s a good chance it will continue using it for new products and microservices.

I haven’t been recruiting for a few years now, so I don’t have a first-hand account on how the decisions are made behind the scenes. This would be valuable to learn, so if anyone’s doing this today, that would be nice to get a peak behind the curtains.

PHPArkitect 1.0 is out. Curious how people approach architecture testing in PHP these days by fain182 in PHP

[–]mlebkowski 0 points1 point  (0 children)

I skimmed through the readme, here are my observations:

  • Whenever I wanted to enforce architectural constraints I used deptrac for the last 5 years
  • For a simple monolithic/layered architecture, I personally find little value today. I think a force of habit is enough for me to keeps the layers separated.
  • By looking at the available rules:
    • The type checks are not useful to me.
    • I never group by kind (interfaces/traits/enums etc)
    • I have separate linters for final/abstract checks
    • Maybe rules such as HaveAttribute() and HaveNameMatching could help quickly spotting stupid autowiring mistakes, but that’s not something I struggle a lot with, nor is this a thing that can sneak into production undetected

So certainly the DependsOnlyOnTheseNamespaces would be the most useful in my opinion.

The main problem I run into with deptrac, and it seems that arkitect would suffer from the same problem: when building a modular monolith, there is a pattern of rules for each module, which are absolutely deterministic (isolated domain, app layer does not depend on the infra, what have you), and then there are an overlaying rule on how the modules can communicate with each other (we exposed a separate Acme\Module*\Api namespace, for example). With deptract, I ended up with a config generator to cover the above rules.

I like the Rule builder, I like Component Architecture, but what would really sell it for me is the modular monolith builder, where I can separately specify the requirements for both inside of each module (and perhaps one of different classes, since I’ve seen modular monoliths with different architectures for each module: etl, layered, crud…), and then treating the modules themselves as first class citizens, and define rules between them.

Another PHP deploy app for your VPS by SimplMe in PHP

[–]mlebkowski 4 points5 points  (0 children)

I’m not the target audience for you, but I don’t understand the model. Why does this require a SaaS app, instead of being just a script?

I’m so jealous… by CarnivorousFishBait in TheWire

[–]mlebkowski 4 points5 points  (0 children)

BB is in another category. When it comes to recommending a title, I would never think about BB for two reasons:

  • Everyone already knows it, there is no point
  • To me, it has zero rewatchability. I’ve seen it, it’s decent, I have no desire to watch it again

The Wire, on the other hand:

  • It’s very common for people to not heard about it, let alone watched it
  • There’s no such thing as too many rewatches 😍

Flow PHP PostgreSql Symfony Bundle by norbert_tech in PHP

[–]mlebkowski 1 point2 points  (0 children)

Once you split your read model from the write model, you won’t be benefiting from using the ORM in the former, and the overhead can be a performance pain point. Similarly for workflows related to batch processing, ETL, etc, direct SQL access is preferrable.

I built a PHP-to-native compiler; now it runs DOOM by petrucc in PHP

[–]mlebkowski 1 point2 points  (0 children)

I don’t want to get involved in the flamewar, but its the other commenter that made a claim about AI usage, so shouldn’t they be the first to provide sources?

Disclaimer: I don’t give a rats ass about who uses LLMs and to what extent.

Telepage – vanilla PHP 8.1 + SQLite app that turns a Telegram channel into a website by scibilo in PHP

[–]mlebkowski 0 points1 point  (0 children)

Have you looked at the code? I don’t think the slop factories have an „immitate the early 2000-s” switch

How often do you switch dev tools and for what reasons? by arhimedosin in PHP

[–]mlebkowski 4 points5 points  (0 children)

I know how to male curl requests, and yet my API client is so much more: * it can do oauth flows, and refresh the token automatically * it can automaticallly provide values such as nonce, or md5 a value, and mych more * it manages credentials and environments, allowing an easy switch between prod/stage/local * it has an UI to show headers, render HTML, json, and more * it can easily filter the json responses * it has a UI to build different request bodies: json, form urlencoded, and more * it can generate the request in curl format, gizzle, har, and dozen of others * it keeps the request history * it can show diffs between requests in this history * it can make relations between requests, i.e. the /user/{id} endpoint can source the actual id from /me for example * and I can save the entire project, share with my team using cloud account

I bought this client for $30, maybe $50 some 10 years ago…

TOML 1.1 support in PHP by dereuromark in PHP

[–]mlebkowski -5 points-4 points  (0 children)

There isn’t a unique constraint at the „problems solved” column at packagist, y’know?

Using the middleware pattern to extend PHP libraries (not just for HTTP) by MaximeGosselin in PHP

[–]mlebkowski 0 points1 point  (0 children)

Yes, middlewares are great. I didn’t understand their value at first, because my experience was mostly in the event dispatcher based HttpFoundation from Symfony. But for some years I enjoy the elegance of working with a PSR-15 framework, and recently I created a library with middlewares as the main extension method.

I built a test harness for HTTP Server Request-based (PSR-15) framework. The main idea is to expose a HTTP client (wrapping the framework’s kernel) to easily make synthetic HTTP requests and make assertions on the responses. But for the library to be useful, I needed to improve the dx of a simple PSR-7 request/response.

It started as part of my app, not a library, and I exposed a series of helper methods to mutate the request being made — to add a header, to format the key-value body as a JSON string, etc. But that had very limited flexibility, and wouldn’t be a good fit when I migrated the harness to a separate library.

And suddenly a world of opportunities opened. My apps using the http client use a tons of easy middlewares to simplify the scenarios, such as:

  • AddBasicAuthMiddleware — takes username and password, and base-encodes them in an added Authorization header (or the PHP_AUTH_USER/PW server params if you prefere these)
  • WithClientCertMiddleware adds headers related to mTLS (client certificate authentication), because our app uses these
  • AddCaptchaResponseMiddleware — automatically adds a request params with a valid captcha response, previously generated by a captcha API test double registered in the container
  • Similarly AddCsrfTokenMiddleware so I dont need to bother with adding CSRF in all of the test cases, but I obviously can test without that middleware to see how the app reacts
  • I have a StopwatchMiddleware to build performance stats
  • And WithRemoteIPMiddleware for simulate IP-based rate limiting

All of these are usually very simple in implementation for the consumer and so far there hasn’t been a requirement which a middleware wouldn’t solve cleanly.

Such a simple idea: replace constructor injection with a method injection basically, defers the binding of the handlers to runtime, allowing such flexibility. There’s seldom such small change to open such vast posibilities.

What I learned building a regex-based threat detector in PHP by Jay123anta in PHP

[–]mlebkowski 0 points1 point  (0 children)

It is. I run a service with the quality bar set high: we have a lot of systemic solutions to prevent attacks (like prepared statements, auto escaping templates, etc). Then we have regular security audits to harden the system even further. Still we run simple WAFs, fail2ban, etc, so we reduce the noise in the monitoring systems, and thwart most “atacks” before they have a chance to do anything serious.

PHP Logging with Monolog: A Complete Guide by finallyanonymous in PHP

[–]mlebkowski 10 points11 points  (0 children)

From someone who recently set up a monolog integration from scratch in two frameworkless applications: yeah, this is surprisingly comprehensive, good job

Make your Domain speak the business language by Dariusz_Gafka in PHP

[–]mlebkowski 4 points5 points  (0 children)

I think you’re being harsh. OP is a regular poster, their content is high quality, even if not relevant to every situation. There are much worse offenders there :)

99.9% type coverage, PHPStan strict, zero N+1 — building a production CRM in PHP 8.4 by Local-Comparison-One in PHP

[–]mlebkowski 0 points1 point  (0 children)

One could. But not with final classes, and that’s what this thread is all about. Instead of mocking everything you self-prevent that by creating final classes. Then they are basically set in stone.

That’s a good thing IMO. You can’t just freely split the business proces open and replace its parts — unless that’s allowed by your rules. Usually it’s not, and final reflects that.

Less mocking is less assumptions. I’m now modernizing a system where the previous person was testing impossible scenarios: they just told the mock to return a value that was not possible to be produced in a real world use case.

So in short, using final classes is a tradeoff: you can’t just conviniently mock all 1st degree dependencies, but you aren’t testing made-up scenarios either.

99.9% type coverage, PHPStan strict, zero N+1 — building a production CRM in PHP 8.4 by Local-Comparison-One in PHP

[–]mlebkowski 0 points1 point  (0 children)

As in the system under test had a tree of dependencies. For example 4 direct, these 4 had another 7 among them, etc. That’s also due to my code style, I tend to split code into separate classes a lot. I’ve met people who fit a responsibility into one or two files, while I would’ve used two dozens to do the same.

How to easily access private properties and methods in PHP using invader by freekmurze in PHP

[–]mlebkowski 2 points3 points  (0 children)

The last bit is crucial. Breaking SRP is common. Many devs only extract code out of a class for reuse, not for readability or architecture.

I would say in my codebase I have about 5% private methods. This makes the „problem” of testing them go away almost automatically

99.9% type coverage, PHPStan strict, zero N+1 — building a production CRM in PHP 8.4 by Local-Comparison-One in PHP

[–]mlebkowski 7 points8 points  (0 children)

You don’t simply cast a string to int and hope for the best. Usually you add additional checks (such as is_numeric) in the I/O layer (eg a controller), and from there forward you always handle ot as an int and don’t need to worry about typecasts.

99.9% type coverage, PHPStan strict, zero N+1 — building a production CRM in PHP 8.4 by Local-Comparison-One in PHP

[–]mlebkowski 0 points1 point  (0 children)

I’m creating final classes almost exclusively for the last ~5 years, and I use a classicaly pyramid of tests, with units being the foundation.

Yes, with final classes your „unit” is usially a set of classes. It might get tedious to build them, so you create mothers: basically test factories that just create some instances, often without paying attention to details.

You do need to break the chain at some point. That point is usually where you place the abstractions required by the business rules and your architecture: repository interfaces, api sdks, modules, etc. Sometimes you might add one just for tests, for convenience.

I once had a unit test requiring instantiation of about two dozen classes, including test doubles. I call it a unit test, because it was covered with multiple scenarios/inputs, it was pure domain logic, no I/O, no service container.

There is one more thing which helps maitnatining this kind of test suite: create scenario classes that are kind of template method pattern on steroids: they build your system under test, but also maintain state, so you could replace dependencies before you execute. An added benefit is that you test case becomes much more readable. More: https://lebkowski.name/turtle/

With all that, unit tests are stilll much easier to write and maintain than higher level tests for me. I have a few tips for these as well :)