Hacker News new | past | comments | ask | show | jobs | submit login
The consequences of living with a legacy PHP framework (yannickmahe.com)
72 points by tnorthcutt on Aug 29, 2013 | hide | past | favorite | 66 comments

This is the consequence of writing code against ANY framework. I don't care if it's Symfony, Zend, etc. in PHP, Rails in Ruby, or Spring, Struts, etc. in Java. The more you lean on a framework, the more you are tied to it and the harder it is to move.

Just look at all the pain Ruby devs have felt moving from various rails versions. https://railslts.com shouldn't have to exist if we were doing our job as software developers.

Using a framework is a HUGE tradeoff. You are trading ease of development for a kind of vendor lock-in where the cost to move goes up with every line of code you write.

Using an architecture that lets you write framework-independant code is a huge win and would keep you out of this kind of trouble. I wrote Obvious Architecture http://obvious.retromocha.com for this reason, but there are plenty of clean architecture examples here: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-arch...

So you write all that functionality that comes with the framework yourself, and then what? It doesn't need improvement? It doesn't need updating to remain compatible with the ever changing technology around it?

As far as I'm concerned, you're digging a hole either way, it's just the shape of the hole that changes.

The bottom line is that there is too much code to maintain (or migrate, or rewrite, depending on the shape of your hole) and never enough resources/people/budget/time to do it.

Everything is a huge tradeoff.

You don't write all the functionality that the framework gives you. You create boundaries between the framework and your code, so that if the framework changes, your app code doesn't have to. It doesn't matter if it's a front end framework, a database ORM, a queue, or a web api. External changes don't need to break your core app.

What you propose may sound great and easy in theory, but in practice it's usually a huge disaster.

The truly useful code of the application will quickly become overwhelmed by the code that tries to abstract away the high-level abstractions offered by the frameworks being used. The boundary or interfacing code you mention ends up becoming a custom framework in and of itself, but usually far more limited than the underlying frameworks.

It's pointless to use a framework in the first place in order to reduce the time and effort needed to build a software system, only to immediately try to abstract it away with a bunch of custom code.

As an industry, we've seen these kinds of systems in the Java world for many years now, and they never turn out well. The performance is awful due to the layers upon layers of abstraction. It becomes extremely difficult to partially, never mind fully, comprehend such a system. This in turn makes even simple changes risky and awkward. And in virtually all cases, the abstractions end up being useless, because the underlying framework is never actually changed at any time. And in the rare cases that it is, a huge amount of work is needed anyway because the code abstracting away the framework never does this perfectly.

The cost of implementing and maintaining the type of abstraction that you propose can easily exceed the cost of rebuilding from scratch software systems that are highly tied to one or more frameworks.

Exactly. Abstraction upon abstraction upon abstraction. I still write to just write plain SQL. (They call it "raw" and it comes with warnings!). That's enough abstraction for me :)

> The bottom line is that there is too much code to maintain (or migrate, or rewrite, depending on the shape of your hole) and never enough resources/people/budget/time to do it.

Everyone says this, but then finds time for FB/Twitter/HN during the day. Something doesn't line up. This is a question of priorities, and people not feeling the effects of hard coupling to a framework.

> Everyone says this, but then finds time for FB/Twitter/HN during the day.

Not to mention extravagant lunch breaks spent chewing food instead of inhaling Soylent, trips to the bathroom and time wasted milling around the proverbial water cooler.

More to the point, the technical debt being discussed here isn't solved by increasing office productivity by 5%.

do you really believe that 20 minutes of time wasting on hn per day somehow translates into a significant amount of dev work that I could have done but didn't?

20 * 5 = 100 minutes

So, yes. It's OK if you don't, but I think it's worthwhile foregoing social media sometimes to work on studying and upping your game.

Besides, you don't always have to be in "OMG not enough time to do this nicely!" mode. Such a mindset is reactionary and generally not conducive to writing robust code. I'd rather go a little slower and not have to return to parts of the codebase later.

Not all minutes are created equally. Spending 100 minutes in a row on code is usually pretty useful; coming back to it for 20 minutes a day is not, especially if we're talking about upgrading to a major upgrade of a framework, which we are.

I would have to second this. When I have a meeting that ends 15 minutes before lunch it is hard to want to work on a task when I know I wont be able to get into the flow.

This is why we don't do away with the 40 hour work week. Some people will always think that working more will solve all of our problems.

Haha, not at all. I'm all for 20 hour weeks.

I do believe that thinking more and working less on work will solve more problems though.

Completely agree.

I wrote against Symfony 1.0 and the upgrade to 1.4 needed a partial rewrite (look, new form library!).

I wrote against Symfony 1.4 and the upgrade to 2.X ..well hasn't happened, a recession got in the way and clients want to spend money on something that'll have results.

I don't mind legacy code - heck I make a good living from it. But I wish framework developers (and everyone online) would agree that slower, more evolutionary progress is OK.

-- A cynical developer, who's seen fads come and go too many times

frameworks and everything, say, post-2003 has been a tragic joke on our profession. We deserve better, but everything JWZ says here is the norm: http://www.jwz.org/doc/cadt.html. Even the majors, like Google, are doing this today. Quality down, fads up.

thankfully symfony 2.3 is LTS now.

the thing about frameworks is that you don't get the goodies unless if you upgrade, but you wouldn't get the goodies anyhow unless if you wrote it yourself.

It's a tradeoff, but usually a worthy one.

Then just don't upgrade. It's not obligatory :)

I hope this point gets more discussion.

It's entirely possible to decouple yourself from a framework and move quickly. It's just that most devs are incredibly lazy, and most frameworks are specifically engineered to make this difficult.

> It's just that most devs are incredibly lazy, and most frameworks are specifically engineered to make this difficult.

I think you mean frameworks are specifically engineered to allow devs to be lazy.

Doctor, it hurts when I couple my code to a framework in an attempt to save time and effort writing boring things I don't care about.

Then stop doing it, silly.

Portability requires effort. It pretty much requires you to not use all-encompassing frameworks. But I'd be shocked if the average JS code slinger today has even heard that word before.

It's essentially true for any language (and its standard libraries).

True, but languages/standard libraries don't break quite like frameworks do. This mostly due to the extreme coupling that a framework induces on client code.

Frameworks mean you get to skip the design step, at the risk of having you by the balls later on.

There is a point to be made about learning how to use a framework up to the point where you're not relying too heavily on it.

I use Yii, for example, and pretty much only utilize permissions filtering, routing, view management, and AR. The form, theme, and other niche tools are all unused.

This way, when upgrades come along I only really need to be aware of controller files, model files, and view files (all php template and raw html, no helpers). Models are auto generated off the schema, so those are a one click fix on a new base.

> "most frameworks are specifically engineered to make this difficult."

This almost makes it sound like an attempt at intentional lock-in which I find fairly unlikely.

Can you elaborate?

Hard coupling to a framework-specified details is tough to remove after the fact. For example, everyone's OK with ActiveRecord's coupling until their test suites are slow. This decision creeps up on them and they have to expend additional energy dealing with it.

It's the tradeoff of simplicity: framework authors want to make things easy (and this is commendable).

With respect, the OP's experience matches anytime that you have dealt with legacy code. Heck, e-ink Kindle devices use Java 1.4. No generics, weird interop with JNI, and so many fewer plugins (think robust encryption, XSS checkers, etc) as a consequence. The experience has nothing to do with the framework, only that the code is legacy and it's too much hassle to migrate forward.

Probably a better way to put it: developing legacy code is like living in the past with the benefit of knowing the future. You miss all of the modern tech and constantly remind yourself how much easier it would be if only you had XYZ. But it's unfair to criticize those past decisions with the benefit of hindsight. When writing my expressive scala code, I sure wish the computer would just know what I mean and auto-complete my code... it would be obvious to one ten years from now :)

Using fear to choose the 'Obvious' framework over choosing Rails or rolling your own seems silly to me given you can find tons more people who know Rails (your boutique shop hopes to grow, right?) and tons more products designed to work with Rails. That ecosystem bonus seems to more than offset any tie-down to an open source framework. Will there ever be Obvious LTS?

You're right that there is a tradeoff in picking a framework, but I think we disagree on the costs behind that tradeoff.

I am not opposed to picking a framework, I'm opposed to make your app a "framework" app just because that's the default state of things. You can certainly pull things into smaller chunks that are loosely coupled, so maybe you use something like Rails for the view, your app is plain old ruby, and you use MongoMapper or Sequel for the DB, but the communication between those layers is done by sending messages, not by hard linking, so that the front or back end can be removed.

Rails all of a sudden is terrible? Switch the routing/views/controllers to Sinatra. Want to move over to something Java based, you can still use a bunch of your core app code via JRuby and maybe slice out bits into Java/Scala over time. Want to switch from Mongo to Postgres, swap out the database module.

My point is, the switching cost doesn't have to be an entire codebase rewrite to move from one thing to another. It only exists that way because the default framework path is tightly coupled by default.

As to if people should use Obvious? Well it's just a pattern of how you put code together. It's not a framework and it's not the only way for people to get the same benefits. I don't care if people use it or not. Use Hexagonal Architecture or Onion Architecture or DCI or whatever the flavor of the week is. It doesn't matter.

The point is, your code doesn't have to be tightly coupled to any framework. There are good options and patterns out there and just defaulting to any particular framework's defaults will lead you down the same path as the OP.

I get the sense we're talking past each other. I don't disagree with a single thing you said; I just don't think that rolling your own adapter so you can swap out concrete frameworks is a silver bullet that fixes the coupling problem. I interpreted the original comment to claim 'Obvious' as such a silver bullet.

My professional career has worked with codebases that have a median age of 5 years and millions of lines of code. Most projects have 50 or so developers across timezones. Say we wanted to switch out rails for sinatra, it simply would never have been possible, even if we perfectly isolated rails from our business logic using an adapter like Obvious. The concrete details most often leak through the adapters -- remember, people are sometimes hurried or sleep deprived or forgetful. We would have had to stage the work, do it in phases just to test properly, and most likely leave the legacy stuff alone -- "If it aint broken, don't fix it."

To be honest, having used Django since 1.3, there are things needed to be done to port to 1.4, 1.5 etc, but they aren't hugely serious.

That's because Django is one of the most sensible frameworks around, with the developers being fully aware of the costs of upgrading, making massive efforts to minimize it and not break backward compatibility unless absolutely necessary.

I think that's one of my favourite things about Django - even though it might not be the literally best thing out there, it's pretty damn good, and the developers understand the concept of maturity.

Shame about WSGI (despite it's benfits) being so inflexible though. It'd be good if there was some sort of "socket gateway interface" for pythonn spec that allowed Python apps to do stuff like websockets. IIRC WSGI cannot do that as it's all about single request/responses.

Might look into what can be done with async stuff (gevent) and uWSGI 1.9.

These consequences are broadly generalizable to "pinning" yourself on any particular version of a software package. The farther behind the current version your pinned version gets, you'll be able to find less help on Google, the ecosystem of compatible third-party packages will get smaller, the number of flaky bugs you'll encounter when upgrading other parts of the stack will get bigger, etc. A business who's still using (say) Windows 2000 on their desktop machines will have all the same problems.

In other words, you don't want to live on the bleeding edge necessarily, but it's a bad idea to let yourself get too far behind it too.

As a longtime symfony user i think the biggest mistake here was to not upgrade to 1.4..Even now the effort to upgrade to 1.4 should be worth it had a lot longer lifecycle, more documentation and alot more people are still using it. I also believe the effort should be fairly small compared to rewriting it using Symfony 2.x. I am currently working on a huge Symfony2 project and we update to the next version asap to avoid these kinds of problems. Its kind of like merging a branch. If you merge master into your feature branch every day and take the time to fix conflicts one by one it will be easy to merge back into master. If you dont, and develop for weeks/months on your own it will be alot of work to merge back.

Can I point out that nearly all of the issues he identified would have still applied if he had used no framework or a home-grown one?

1. Need to update to support newer PHP versions. Check.

2. Lack of community support. Check.

3. Can't draw on 3rd party plugins. Check.


Plus he would have had the burden of writing his own in the first place - or the overhead of coding without a framework.

So - how does this lead to the conclusion that he would have been better off not using Symfony?

The lesson I drew was "choose your framework wisely and don't accrue technical debt".

It's good to point that out. I think he realizes that, but I'm not sure most of HN does.

It is relatively trivial to upgrade from 1.0 to 1.1 and 1.2 is as far as you need to go to be able to use a more modern PHP. The biggest changes are how the controller interacts with the model and views, which can be done with a sed script in most instances.

Most plugins for 1.2 offer versions for both Prototype and jQuery.

In general, Symfony 1.* was easier to work with than 2.0. Symfony 2.0 feels very much like a Java project in that they prefer mounds of configuration files, reflection, annotations, etc, all to do something very simple - routing and view management.

Same thing happening in Android development right now. You may have spent years working with Eclipse and Ant and the ADT plugin for Eclipse to write Android apps. Personally I have dozens of apps written using these. But now everything new is happening on Android Studio and Gradle, the new IDE and build system. If you want to use new features like binary Android library packages, you have to switch to the new tooling.

While its true the official build system is slowly lurching its way over to gradle, this is nothing like what the author is experiencing with Symfony. Android + ant is still fully functionally and has tons of documentation and community info. Switching from ant builds to gradle is not difficult and doesn't impact app development, Eclipse/Intellij/Android Studio all can build and work with projects without gradle.

AFAIK there will be comparable tooling for Eclipse once the new build system is officially 'ready for production'.

Symfony is somehow able to make PHP programming seem very elegant... I never understood all the hate against PHP while tucked safely inside the framework. The main drawback to Symfony is the endless amount of configuration that is done through YAML files and pure PHP. The configuration files are spread throughout the project dir and can be a bit confusing. To paraphrase a famous quote: "I would rather have one configuration file that configures 100 things than 10 configuration files that configure 10 things". After migrating to Symfony 2.0, one day I wanted to make a simple column change in my database and it took me TWO freakin' days to figure out how to properly configure the ORM! I've since abandoned PHP/Symfony/Javascript for Clojure/Clojurescript and I haven't looked back!

I completely feel your pain with regard to Symfony. That, and the required verbosity in coding left me feeling lost in a language I thought I knew.

Even after a couple projects I still didn't "get it." Most of my time was spent in the docs and stack overflow trying to learn the "symfony way" of doing things rather than just getting it done.

- Too much nesting, both in file layout and yaml configurations - Too many different ways to do things (YAML, PHP, .ini, file annotations) - Too verbose when coding (namespaces, long class and method names) - And don't get me started with Twig

I took those hard knocks and tried to write my own mini-framework, which only taught me why you don't write frameworks. It is really hard to do well.

Then I found laravel [1] and have been impressed. It is more opinionated than Symfony and feels more cormfortable to develop on. Less configuration, less verbosity. I combed through the docs and had a project up and running in two days.

But here is the real nugget, kids. Using a framework on a long-term project is like marriage. It takes commitment. You will be in it for a while, so you had better make sure you can live with it. You have to invest your time and effort into it to understand it as much as possible -- warts and all.

What kind of apps or websites were you developing sheraz? I'd like something less complex than Symfony, but Laravel doesn't seem as feature-complete for complex applications. Form definitions seem much more lightweight (I build 9+ page loan application forms, multi-page legal forms with repeating regions, add-remove rows etc), APIs and REST interfaces - the works. I want to change framework, but I get the impression most of the others have a smaller-project sweet spot.

[And yes, I know large stuff can be built with the others, like it can with Drupal. But does the framework make it as/more easy than Symfony, that's the question?]

A free rant :): I hate the Doctrine ORM for it's hideously bad documentation (either missing information or written by core devs for core devs -- I can't contribute to improving it as I don't understand it well enough!) yet I appreciate a 'real' ORM vs an ActiveRecord+QueryBuilder system. Gah.

I've built a few digital asset management apps for fortune 500 companies, CRUD apps for non-profits, and several different startup ideas (sites, mobile, etc).

Nothing I've made has required a lot of input form complexity, which seems to be Symfony's strong suit.

I think you might be right about the project sweet-spots. Symfony certainly seems equipped to handle workloads you describe -- I've not seen form input validation as complex as Symfony.

Is Silex too heavy or too light for your usage?

I think too light, but I don't think I've ever got the concept straight in my head. I thought it was a mapper from a URL parameter to a function - the first two code examples in http://web.archive.org/web/20130402141837/http://edorian.pos... are what I understood it to be.

TL;DR: I think Silex has changed a lot since I looked at it. I can't give you a good answer.

Silex is definitely a good lightweight alternative. For enterprise work Symfony 2 is a better choice, but if you need to throw things together (but need to keep the option of adding more features without writing them yourself) you can easily integrate a bunch of the Symfony 2 components into Silex.

I wouldn't call Silex "lightweight". Slim, however, is very lightweight and a pleasure to use: http://slimframework.com/

The file annotation method of configuration made me think I'd had a stroke at first. Configuration in /* comment blocks */ seemed like a weird, weird, weird idea.

Did you bother reading the extensive documentation? You can quickly figure out how to do this within 10 minutes for your first time.

I'll be interested to follow the comments about this problem, because it seems to me that it can be generalized to working with any legacy backend system. In my first job it was an 8 year old custom CMS built in ASP classic, then it was a home-grown PHP CMS, then a very large Java BE codebase - in each case I felt that the existing system made very aspect of development more difficult than it "could be" with a more current framework (1/3rd productivity loss was a major underestimate in some cases).

I am interested in people's experiences with using a third-party system and trying to keep it updated versus using an in-house system that gradually becomes more difficult to update/maintain.

Sometimes a state of permanent updates can be just as limiting.

I think it's probably generalizable to any codebase large enough to have a learning curve.

I am not expert, but I have listened to a course where the teacher said that we should use many frameworks. When you develop a project for a client, you select the current best framework and you do not change until you really need to change. Then when you have a new project for a new client, you use the new best framework.

I do not know if it is feasible in all cases. Having many frameworks allows to anticipate the problems, cost and benefits of a migration. I think it is interesting for developers who will have more interesting work. The cost of many framework may be compensate by the fact that it is easier to associate a migration cost to a client.

As I see it if you are developing something small for a client, you want to get something created ASAP get it out and forget about it. So yes, then it makes sense to use the current best framework and write code that is tightly coupled with it.

But when you start to create larger systems, you will have to think about maintaining the code, adding new features and fixing bugs. Then it is not so fun if your code depends too much on a framework and you don’t update it when new versions are released. It is not fun googling for something and in the one result you get someone is pointing out that you are using an obsolete framework, and noticing that the post is 10 years old. (Did happen with some software I used to be developer on)

There is also an answer for that: do not build large system. Split them into largely independant parts (I think this is called silo architecture). When one of your silos get outdated, you replace it.

> (I think this is called silo architecture)

Might be called that now. When I was working on big systems it was called Service Oriented Architecture.

This is why I strongly believe in writing framework-agnostic code. The extra effort of splitting even small bits functionality into decoupled components can save so many headaches in the future.

When I'm writing a new feature, I always try and code it as if I'm going to release it as a standalone library that could easily work for other people regardless of what framework they're using.

Stuart Herbert wrote a lot about this: http://blog.stuartherbert.com/php/php-components/

The company I work for also had this problem.

The solutions was in fact simple: we told our customers we wouldn't add any features or changes other than bugfixes. When you are telling the software is outdated and the support is gone they all understand it's time to move on [1].

Most of the time the customer also wants to get rid of the outdated website/webapp. So it's also a good reason to start something new.

[1] Ofcourse this doesn't work for all customers.

The way you describe it, I understand the customers moved to a competitor and the company went out of business.

Or did you have a new version ready and at (near) feature parity with the old version? As the article describes, that investment can become very large when you put it off for too long. And the reasons they had to put it off were, at least initially, quite valid.

Ofcourse there should be a better alternative at the time you tell your customers to move on. But no, they didn't run to competitors. I don't want to sound very arrogant, but when your work is good, customers will stay because they trust you.

I don't see that approach working in any competitive product marketplace. This is the kind of candy you don't want to throw to you competitor.

Anecdotal, there's a company that built their core product on Symfony 0.9x, and never upgraded. That was started around 6 years ago. The company is now worth 1+ billion on nasdaq, and still relies on Symfony 0.9x for the core functionality.

From a development point of view it sucks. Ask any developers.

From the business point of view, staying away from the kind of 6 month no feature s-bugs-only period you're talking about, is probably the reason it could beat its main competitor, and succeed the way it did.

How much functional/end-user automated testing do you have? That's probably the biggest roadblock to roll with things like 1.0 to 1.x upgrades. Why are migrations considered risky? Is it risky because the functionality will break? Or is it risky because the next point release (say 1.2) is considered unstable?

Because the latter fixes itself with time as the community tests version 1.2 and patches come out, but not having tests for your own code that don't rely on the framework prevents you from being able to move fast on anything but the smallest of refactorings.

I think that's how you can get yourself out. Ruthlessly write end-user acceptance tests (something that drives a browser, headless or not, Selenium, PhantomJS/CasperJs, etc etc) that verify all your functionality. Only once you can quickly and automatically verify correct operation can you then do something like a framework migration (even if to latest Symfony 1.x).

I started TouristEye.com 4 years ago with Symfony 1.1. We kept pace with the new releases (updating when 1.2.2, 1.3.2, 1.4.2 was out). Last November we decided to simplify our website and completely change our website, so we felt it was the right time to do the migration. It took 5 months (myself as the backend of the website & api, and another developer as the frontend). It was a big rewrite, but the code now is so much better to maintain and learn. We are right now using 2.3, and I'm way happy coding :)

About your case, I agree with you that the best way for you is to add component by component, extracting and encapsulating functionality so you can use Symfony2, Zend or whatever framework you want in the future. Go for a service oriented architecture. And let's hope you have everything tested!

This is a problem with software in general. Lazy developers or ignorant bosses stagnate the code to the point where it requires a massive rewrite to bring it up to speed.

Right now I maintain about 70/30 old code to new code. Most of the old code is because previous developers didn't care at all and were more interested in job stability than code stability. You make a conscious effort to not follow the trends with the framework and thus can only blame yourself for the outcome.

I think the lack of reusability comes in object-oriented languages, not in functional languages. Because the problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. - Joe Armstrong, creator of Erlang. As quoted in Coders at Work: Reflections on the Craft of Programming by Peter Seibel.

It's not just PHP, if you're stuck in Rails 2 (let alone somehow Rails1?! ) you're going to have similar problems.

It is a problem -- I have apps that i only barely got upgraded from rails 2 to 3 before 4 came out. Hopefully upgrading to 4 won't be as much of a nightmare... but I'm still procrastinating it, even though I know if I wait too long to do it it will just get worse.

How big is this app? 6 months to port from one mvc framework to another seems quite excessive.

Talk to any ColdFusion developers.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact