I'm starting to build a bit of antagonism to all-encompassing frameworks (e.g. Spring, Larvel, Phoenix, etc.), because while they are productive to build new things with, I seem to always have the same issue on legacy projects built with them.
It always seems to be a challenge to upgrade dependencies for these projects. Its usually because (in building the thing) one can't fully follow the "prescribed" way of doing things with the god framework, because each project has to deal with a niche infrastructure environment and/or business context that requires some hack or additional dependency. Then when you need to, say, upgrade a language version, you can't follow the god framework's guide for doing this (if there even is a decent one) because it will break your workaround. So you end up with this hodgepodge which never gets updated until it reaches a critical point where it cannot continue to run on your infrastructure, and it forces a big migration project.
Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
Web frameworks for me are one of those things that's "great until it isn't".
If you're making a simple app then web frameworks can feel downright magical (like the original "Build a blog in 15 minutes with Rails" demo [1]), but for anything that gets even remotely complicated, I find that they generally just get in the way.
I personally have grown to prefer the "mid-level" HTTP setups, like Express with Node.js or Vert.x with Java.
In the Python world, I see this as the microframework (Flask-esque) vs macroframework (Django). I will take Django every single time.
Flask prescribes so little that every project is a snow flake. Which of the N available options will you pick to handle auth/templating/cookies/email/whatever. Real decision fatigue when trying to enable core functionality. Extra special is that many of these libraries are single author creations, so maintenance and security are a mixed bag.
Django - every project roughly looks the same. You get so much out of the box that you must have special requirements if you must supplement with libraries. Since so many bits are first party, you have greater confidence that code is being maintained/checked for security problems.
The reason Go does not have a grand framework is that the language has a severely underdeveloped type system, which makes building complex libraries that meaningfully complement each other overly difficult. I waited nine years before starting on my first Go database toolkit so I could use generics. I succeeded, but can't shake the feeling that I know I had a better experience doing it with Java in undergrad. Being able to map/filter/reduce from a result type into another generic type would be a complete game changer. Being able specify union types would eliminate my need for the "any" type. Being able to overload would clean up a lot of code. It needs more time in the oven.
Yep, In my domain only Go/Rust are useful. The opinionated framework culture never fits the bill. I think Rails/Laravel/Django are great when you have a beaten path for relational DB crud.
PSR to the rescue! For the past ~5 years I've been only using PSR-compatible components, with no framework whatsoever. For both enterprise-grade projects and small services. The reason was the same - those all-encompassing frameworks in long run just don't work. Too many constraints, too much hustle maintaining/updating.
> It always seems to be a challenge to upgrade dependencies for these projects. Its usually because (in building the thing) one can't fully follow the "prescribed" way of doing things with the god framework, because each project has to deal with a niche infrastructure environment and/or business context that requires some hack or additional dependency. Then when you need to, say, upgrade a language version, you can't follow the god framework's guide for doing this (if there even is a decent one) because it will break your workaround. So you end up with this hodgepodge which never gets updated until it reaches a critical point where it cannot continue to run on your infrastructure, and it forces a big migration project.
Can you give any specific examples?
I'd like to see which of these are open source. And whether or not they're funded for maintenance.
I've been out of web dev for a few years now, but my issue with frameworks was always the ORMs. Simple CRUD apps always worked fine, but when I had to optimize SQL queries or create something more complex, I would end up having to add hacky additions to the app that always broke upgrades.
I've found this for web frameworks as well. The time you spend learning the framework's abstractions could just be spent picking a queue library or whatever you need and adding it to your Go server.
In Laravel, the issue is that the framework is sold as "productive" as default. There is no real "beef" to the framework though, IMO. It is better today, but historically it is just a wrapper around symfony with some dependency injection through reflection, questionable serde, tons of magic, and with some unique takes on templates and routing, which are arguably not very good takes? Maybe components are better, but blade in general seems backwards as a template language.
Ever want to type `$model->foo instead of $model->getFoo()` but then have `$model->foo` magically call `$model->getFooAttribute()`, but fall back to `$model->getAttribute('foo')` if that method doesn't exist? Then that magically calls some casting methods, and possibly even fetches infinite records from a remote store? It is so artisan, bro. I can tell you more if you got five minutes.
> So you end up with this hodgepodge which never gets updated until it reaches a critical point where it cannot continue to run on your infrastructure, and it forces a big migration project.
This matches my experience, literally took months to migrate an older Spring project to something with fewer CVEs and bugs. Created some new bugs and issues along the way, including one where compiling it on Windows would produce a .jar that runs fine, whereas compiling it on Linux changed something in how the Spring beans are initialized, leading to it failing to even start (the settings for allowing lazy initialization changed nothing).
> Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
Yes and no. If you only wire things up, then sure. But depending on how much code your devs have to write (and depending on the devs), you might actually end up with a bespoke mess if you have to dig into writing various base mechanisms (think transaction handling, scheduled tasks, task pools for parallel execution, key/value stores and caching, validations, auditing and metrics, file uploads and downloads etc.) - one that will have less documentation than something like Spring Boot, you won't be able to ask anyone how to solve issues in it, alongside sometimes just having architectures that neither scale nor work properly, because it isn't something battle tested over literal decades.
> I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
I still agree with this, to me it feels like the correct approach is indeed to give you most of the tools you might need for the technical bits and make you (or other devs) only write a bit of glue to wire everything up, to order how data moves through your system (resources, services, validators, repositories etc.) according to whatever business rules you might have. Things really go south when you miss out on that detail.
In the Java land, I think Dropwizard is a good example of that: it uses a bunch of mostly idiomatic libraries that are well tested, without being quite as rigid as Spring (and Spring Boot), letting you set things up as you please and also not getting in the way too much: https://www.dropwizard.io/en/stable/getting-started.html
In Go, I really like that a lot of the stuff is already present in the standard library.
> In short, the modern PHP ecosystem gives us the best of both worlds: the ability to build quickly and confidently in PHP, while still having powerful options (C, Rust, Go) for performance-critical parts. This hybrid approach lets us stay productive without sacrificing speed where it matters most.
I understand this for a large codebase where rewriting is not feasible.
But if that wasn't the case, a C# APIs achieves both speed of development and execution in my experience. You'll rarely need to reach for C++ or Rust.
PHP is great but the language still doesn't allow things like typed arrays. It will happily accept string in a array of dates, for example.
>It will happily accept string in a array of dates, for example.
Yeah theres a bunch of oddities that rear their head from time to time.
I've had one peculiar JSON de-serialize bug lately that really threw me for a while. I normally do the json_decode() with the second arg set true, which yields an assoc arr. This doesn't tell the whole story though.
IF the key is numeric when decoding, PHP will make its key an int! and not a string like the rest. I'm guessing it does the equivalent of an is_numeric() check or something.
This yields an array with keys which could be ints and strings :/
Still for all its warts though it is a fantastically Frankenstein of a language!
Author here. thanks for reading my post.
actually you still don't need rewrite. running php with workers (swoole, frankenphp, ...) may be as fast as node.
and for typed array php has static analysers like phpstan. it support generics and typed arrays with typed comments.
Joined {{company}} when everything was using 5.4, there was a big distaste of PHP back then.
But as PHP have released newer versions I'm convinced our migration away from PHP (which is just finishing) is probably a step backwards _now_ that PHP is awesome.
Everyone still thinks it is like 5.x days, it really isn't.
I'm not so sure: If you think about hiring talent, there's a perception in the wider industry about PHP (rightly or wrongly, let's not debate that here) that'll prevent access to a lot of great developers. So even if not warranted anymore on technical merits anymore, in terms of employer branding, I'd say migrating away from PHP is helping.
There's also all sorts of interesting experiments, like ngx-php, which basically embeds PHP via Zend API inside an nginx binary: https://github.com/rryqszq4/ngx-php
I bit the bullet rewriting my app from PHP to Go and it paid off for my company, we're talking 20K lines of PHP code, reduced to 4K lines of Go and with the added efficiency gains with it.
I think some orgs just need to take the jump and plan a rewrite, add tests (easier with Go) and just do this if they are a PHP shop, I would say it's worth it.
Instead of blending Rust/PHP or Go together and having an unmaintainable mess of a codebase.
How did you reduce LoC with a move from PHP to go?
Go is a pretty verbose language, whereas for me PHP is somewhere in the middle of the pack in terms of verbosity (Haskell would be on the terse side, enterprise Java and Go on the verbose end, particularly due to the constant error-checking after every function call).
i don't recommend rewrite in anycase (had done 2 successful rewrite before but still i don't choose that my self) and new php run times can may be really fast. you can checkout benchmarks. swoole for instance if used with all the functionalities like its specific caches may be so fast (in some cases as fast as Go)
Sometimes I think we should go back to basics: pixels, data, latency / bandwidth. The web is an optimization problem in the sense that we want to render correct pixels at perceptual speed given latency and bandwidth constraints.
It should be more like: what pixels is the user about to see? What data is need to set the the pixels? What data is likely needed next and optimistically pre-fetch - something like that.
In https://github.com/timschmidt/alumina-ui I've been building for WASM using the egui toolkit which just accepts an HTML canvas the size of the browser and starts shouting WebGL at it.
I get to forget about HTML and Javascript, CSS, most of the complication of the browser and web, and just write an application in my favorite language which will run fast and deliver GL accelerated graphics to it's users.
I am really happy with WASM / WebGL for being abstractions which allows for this.
Thinking about user seeing pixels is seeing just a part of the picture. As all software projects you don't optimize just for immediate user experience but also development time.
Time to first draw rarely coincides with development time.
Very curious what sort of workloads are being talked about here that have the intensity that have C or Rust or Go extensions are necessary? I can certainly believe they exist but I'd be really interested to find out more and why it makes sense to add this complexity into the stack and not solve in other ways.
The one thing I don't like about PHP is that the whole application is bootstraped (and autoloading and the configuration is re-evaluated) in every single http request. Sure thing there's cache and all, but it just doesn't feel right (compared, to, for instance, an http server written in golang)
There are well documented and production-ready libraries that you can use to run your own servers with PHP alone, no need for fpm or mod_php. PHP's JIT is pretty impressive and you would be blown away by the results.
You're right. It's a completely asinine approach. Especially when PHP itself is used as a templating language.
And solutions that try to fix this (custom templating engines, runtimes that run the whole thing inside a continuous PHP process) are simply putting lipstick on a pig.
The solution is to use a language that wasn't originally called "Personal HomePage"
FrankenPHP sounds promising, but in reality it is a weirdo: no one uses PHP without modules. Where is the list of PHP modules supported by FrankenPHP? Is it possible to compile it with some extra PHP modules? How? I see it is tightly bound to Caddy. I am not much familiar with that webserver, I would prefer nginx, but there's not a single guide mentioning if that's possible to use nginx with FrankenPHP (as a php-fpm replacement). Also, either Caddy itself, or FrankenPHP's docker image is quite opinionated in regards to using let's encrypt certificates and it is not trivial at all how to make it work via HTTP (if something external would provide SSL) or using own certificate.
When I do stuff like this, I just write the front app in the new/fast language, then reproxy the stuff not written in the fast language to the legacy app. You can even add middlewares or caching or metrics in the new app for requests going to the old one, as you can run (fast) code around both the request and the response.
It’s the best of both worlds - the new app gets to see all of the traffic, but doesn’t need to implement 100% of the routes. Any added to the new app can just take precedence over the old one, carving out the path-space that gets reverse proxied.
It seems like doing FFI for this is overly complex; I’d rather take the small perf hit of doing another request to a different process.
One of these is not like the other. Go is also garbage collected. Embedding a garbage collected language inside another means you have two garbage collectors fighting each other.
I tried to propose this with Ruby and Rust. We have a super old Rails monolith and want to hyper optimize just a few endpoints. Simply allowing Rust to "poison" the monolith a bit makes gradual adaption very easy. And you keep a lot of the productivity gains of monolith. But people just seemed to prefer full on network boundaries and separate services.
Bet you don't miss Python's massively lackluster performance when compared to PHP though! Nb. I use both for diff things (good luck instrumenting ai stuff with PHP!) but the fact that I have to reach for C extensions for python to even get a basic loop to run at reasonable speed remains peculiar/scary for me.
I owe a large part of my career success to PHP when I learned it back in the day. But recently I picked it up because I had to do some maintenance work and The package management experience was really, really bad.
I really think there's a big opportunity for somebody to create the astral.sh for PHP.
With a proper package manager, PHP can do way more than what it presently can.
author here. thanks for reading my post. i didn't suggest php for all type of projects. i don't choose that myself. what i just mentioned if the only reason to choose something else for responding some apis faster you still may continue in php for that.
PHP really isn't that different from Ruby or Python these days. But, I can see the perspective where none of those 3 are valid solutions given newer better options like NodeJS and Rust.
One of the reasons I like Perl is because of its high committment to backwards compatibility.
I like PHP because it's so easy to set up an installation of my app, but the breaking changes have bit me hard in the past, so I try to minimize its use.
as i mentioned we just choosed frankenphp which is officially supported by php foundation. also only less than 5 percent of our code base is in Go. i don't see any problem to hire developers.
liampulles|6 months ago
It always seems to be a challenge to upgrade dependencies for these projects. Its usually because (in building the thing) one can't fully follow the "prescribed" way of doing things with the god framework, because each project has to deal with a niche infrastructure environment and/or business context that requires some hack or additional dependency. Then when you need to, say, upgrade a language version, you can't follow the god framework's guide for doing this (if there even is a decent one) because it will break your workaround. So you end up with this hodgepodge which never gets updated until it reaches a critical point where it cannot continue to run on your infrastructure, and it forces a big migration project.
Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
tombert|6 months ago
If you're making a simple app then web frameworks can feel downright magical (like the original "Build a blog in 15 minutes with Rails" demo [1]), but for anything that gets even remotely complicated, I find that they generally just get in the way.
I personally have grown to prefer the "mid-level" HTTP setups, like Express with Node.js or Vert.x with Java.
[1]
3eb7988a1663|6 months ago
Flask prescribes so little that every project is a snow flake. Which of the N available options will you pick to handle auth/templating/cookies/email/whatever. Real decision fatigue when trying to enable core functionality. Extra special is that many of these libraries are single author creations, so maintenance and security are a mixed bag.
Django - every project roughly looks the same. You get so much out of the box that you must have special requirements if you must supplement with libraries. Since so many bits are first party, you have greater confidence that code is being maintained/checked for security problems.
evantbyrne|6 months ago
fozdenn|6 months ago
zakirullin|6 months ago
some_furry|6 months ago
Can you give any specific examples?
I'd like to see which of these are open source. And whether or not they're funded for maintenance.
billy99k|6 months ago
b_e_n_t_o_n|6 months ago
N2yhWNXQN3k9|6 months ago
Ever want to type `$model->foo instead of $model->getFoo()` but then have `$model->foo` magically call `$model->getFooAttribute()`, but fall back to `$model->getAttribute('foo')` if that method doesn't exist? Then that magically calls some casting methods, and possibly even fetches infinite records from a remote store? It is so artisan, bro. I can tell you more if you got five minutes.
KronisLV|6 months ago
This matches my experience, literally took months to migrate an older Spring project to something with fewer CVEs and bugs. Created some new bugs and issues along the way, including one where compiling it on Windows would produce a .jar that runs fine, whereas compiling it on Linux changed something in how the Spring beans are initialized, leading to it failing to even start (the settings for allowing lazy initialization changed nothing).
> Using a selection of libraries to build up the elements of a web service, and creating your own high-level abstractions for utilizing them, does require an additional time investment, but it leaves you in more control to do upgrades piece by piece, and to pivot the way things work when it is needed.
Yes and no. If you only wire things up, then sure. But depending on how much code your devs have to write (and depending on the devs), you might actually end up with a bespoke mess if you have to dig into writing various base mechanisms (think transaction handling, scheduled tasks, task pools for parallel execution, key/value stores and caching, validations, auditing and metrics, file uploads and downloads etc.) - one that will have less documentation than something like Spring Boot, you won't be able to ask anyone how to solve issues in it, alongside sometimes just having architectures that neither scale nor work properly, because it isn't something battle tested over literal decades.
> I feel like the Go ecosystem follows the latter approach more than most, and it was bit of a mindset shift for me at first, but I've grown to appreciate it.
I still agree with this, to me it feels like the correct approach is indeed to give you most of the tools you might need for the technical bits and make you (or other devs) only write a bit of glue to wire everything up, to order how data moves through your system (resources, services, validators, repositories etc.) according to whatever business rules you might have. Things really go south when you miss out on that detail.
In the Java land, I think Dropwizard is a good example of that: it uses a bunch of mostly idiomatic libraries that are well tested, without being quite as rigid as Spring (and Spring Boot), letting you set things up as you please and also not getting in the way too much: https://www.dropwizard.io/en/stable/getting-started.html
In Go, I really like that a lot of the stuff is already present in the standard library.
hu3|6 months ago
I understand this for a large codebase where rewriting is not feasible.
But if that wasn't the case, a C# APIs achieves both speed of development and execution in my experience. You'll rarely need to reach for C++ or Rust.
PHP is great but the language still doesn't allow things like typed arrays. It will happily accept string in a array of dates, for example.
ThinkBeat|6 months ago
PHP is really nice if you dig into it, it includes so many great functions and functionality built in for creating web stuff.
It also has a number of issues,. but to quikly put something together PHP take the win in my limited opnion.
jofla_net|6 months ago
Yeah theres a bunch of oddities that rear their head from time to time.
I've had one peculiar JSON de-serialize bug lately that really threw me for a while. I normally do the json_decode() with the second arg set true, which yields an assoc arr. This doesn't tell the whole story though. IF the key is numeric when decoding, PHP will make its key an int! and not a string like the rest. I'm guessing it does the equivalent of an is_numeric() check or something.
This yields an array with keys which could be ints and strings :/
Still for all its warts though it is a fantastically Frankenstein of a language!
honorary-hickup|6 months ago
While completely true, you are using static analyzer anyway which won’t let you do this.
The generics support will likely come in the near future, there has been momentum in it again: https://thephp.foundation/blog/2025/08/05/compile-generics/
avan1|6 months ago
newuser94303|6 months ago
1a527dd5|6 months ago
But as PHP have released newer versions I'm convinced our migration away from PHP (which is just finishing) is probably a step backwards _now_ that PHP is awesome.
Everyone still thinks it is like 5.x days, it really isn't.
criemen|6 months ago
IshKebab|6 months ago
It's definitely better, but awesome? That's a huge stretch.
tomrod|6 months ago
avan1|6 months ago
klaussilveira|6 months ago
https://github.com/el7cosmos/pasir
Which uses the following Zend API bindings for Rust:
https://github.com/davidcole1340/ext-php-rs
There's also all sorts of interesting experiments, like ngx-php, which basically embeds PHP via Zend API inside an nginx binary: https://github.com/rryqszq4/ngx-php
And workerman, which has a hybrid backend of asio libraries, so you can get pretty fast runtimes: https://github.com/walkor/workerman
imcritic|6 months ago
avan1|6 months ago
conceptme|6 months ago
avan1|6 months ago
colesantiago|6 months ago
I think some orgs just need to take the jump and plan a rewrite, add tests (easier with Go) and just do this if they are a PHP shop, I would say it's worth it.
Instead of blending Rust/PHP or Go together and having an unmaintainable mess of a codebase.
criemen|6 months ago
Go is a pretty verbose language, whereas for me PHP is somewhere in the middle of the pack in terms of verbosity (Haskell would be on the terse side, enterprise Java and Go on the verbose end, particularly due to the constant error-checking after every function call).
coolgoose|6 months ago
Php isn't perfect but it has a lot of shortcut syntaxes that go just doesn't have
NeutralForest|6 months ago
tayo42|6 months ago
Ive done do rewrites of stuff in python and it gets really verbose, plus dependency injection patterns for testing.
unknown|6 months ago
[deleted]
avan1|6 months ago
osigurdson|6 months ago
It should be more like: what pixels is the user about to see? What data is need to set the the pixels? What data is likely needed next and optimistically pre-fetch - something like that.
timschmidt|6 months ago
I get to forget about HTML and Javascript, CSS, most of the complication of the browser and web, and just write an application in my favorite language which will run fast and deliver GL accelerated graphics to it's users.
I am really happy with WASM / WebGL for being abstractions which allows for this.
singinwhale|6 months ago
unknown|6 months ago
[deleted]
trog|6 months ago
dakiol|6 months ago
klaussilveira|6 months ago
https://reactphp.org/
https://www.php.net/manual/en/book.ev.php
https://bitbucket.org/osmanov/pecl-event
https://www.workerman.net/
duskwuff|6 months ago
https://frankenphp.dev/docs/worker/
PetahNZ|6 months ago
mhsdef|6 months ago
Intrinsically minimized state (to a certain degree).
creatonez|6 months ago
And solutions that try to fix this (custom templating engines, runtimes that run the whole thing inside a continuous PHP process) are simply putting lipstick on a pig.
The solution is to use a language that wasn't originally called "Personal HomePage"
thr0waway001|6 months ago
imcritic|6 months ago
supriyo-biswas|6 months ago
You usually build the modules yourself in the Dockerfile, for example for the "pgsql" module:
And for http, you just put the following in the Caddyfile:slim|6 months ago
amqp,apcu,ast,bcmath,brotli,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,lz4,mbregex,mbstring,memcache,memcached,mysqli,mysqlnd,opcache,openssl,password-argon2,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pdo_sqlsrv,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,xz,zip,zlib,yaml,zstd
https://github.com/php/frankenphp/blob/main/build-static.sh#...
sneak|6 months ago
It’s the best of both worlds - the new app gets to see all of the traffic, but doesn’t need to implement 100% of the routes. Any added to the new app can just take precedence over the old one, carving out the path-space that gets reverse proxied.
It seems like doing FFI for this is overly complex; I’d rather take the small perf hit of doing another request to a different process.
avan1|6 months ago
ok123456|6 months ago
RainyDayTmrw|6 months ago
maurice2k|6 months ago
https://roadrunner.dev/
resonious|6 months ago
porker|6 months ago
dingdingdang|6 months ago
vadepaysa|6 months ago
I really think there's a big opportunity for somebody to create the astral.sh for PHP.
With a proper package manager, PHP can do way more than what it presently can.
porker|6 months ago
preinheimer|6 months ago
avan1|6 months ago
77pt77|6 months ago
Not only that, but now we have these "frankenstein" solutions with all the interop problems on top of PHP.
Just shows that as a species humans really can't learn.
avan1|6 months ago
phendrenad2|6 months ago
forgotmypw17|6 months ago
One of the reasons I like Perl is because of its high committment to backwards compatibility.
I like PHP because it's so easy to set up an installation of my app, but the breaking changes have bit me hard in the past, so I try to minimize its use.
Together, it's a great combo.
phplovesong|6 months ago
unknown|6 months ago
[deleted]
honorary-hickup|6 months ago
sublinear|6 months ago
avan1|6 months ago