PhpGit



  • TL;DR: Customers each have their own branch in the version control system.

    Currently we have one master branch for our PHP application in a shared repository. We have more than 500 clients who are subscribers of our software, most of whom have some customization for different purposes, each in a separate branch. The customization could be a different text field name, a totally new feature or module, or new tables/columns in the database.

    So take "The Real WTF is PHP"... and throw in "The Real WTF is Git" (since that's an interesting thread in it's own right).


  • Discourse touched me in a no-no place

    @WernerCD said:

    "The Real WTF is PHP"... and throw in "The Real WTF is Git"

    Somewhere there's a blakeyrat short-circuiting.


  • BINNED

    @WernerCD said:

    The Real WTF is PHP

    Nope, sorry, not this time. It's perfectly possible to write modular code in PHP. You can even do decent enough dependency injection if you're slightly clever about it.

    This time, TRWTF is devs. Sorry.



  • If you have this much of a WTF without even seeing the code... I shiver to think of what the actual code looks like. I have a funny feeling the code isn't very modular...


  • BINNED

    True. But as much as I like to bash PHP, the language itself cannot be blamed here. I mean hell, WordPress' code is a steaming pile of 💩, but it has plugins up the wazoo! And they work!

    Well... they tend to get into arguments with eachother and making them all work together is like herding cats, but given how much the platform itself sucks they actually work pretty well.


  • Winner of the 2016 Presidential Election Banned

    This is pretty much what I thought upon seeing the thread title. The only reason he hasn't commented is because he's writhing on the floor.



  • @WernerCD said:

    Customers each have their own branch in the version control system.

    Well, it's not that bad, I mean you'll want to keep branded assets, maybe a chunk of code will change here or there...

    @WernerCD said:

    We have more than 500 clients

    ...oh.


  • Notification Spam Recipient

    Maybe I'm just odd but I kind of want this job.... given that I'm given full control to do what I want and maybe a nice closet to hide a couple skeletons... Maybe a license to kill...

    *edit sanity kicked in. Fucking hell!


  • Discourse touched me in a no-no place

    @DogsB said:

    Maybe I'm just odd but I kind of want this job....

    Yes.



  • Although I do see the WTF here, I can't help but wonder how much worse it could have been. You can see exactly when a client was onboarded, which changes to trunk were made that have or have not made it into the client's code, and who to blame when something goes wrong -- things that are much more difficult with 600 folders. And having one unified DB schema would certainly make migrating changes easier, but then you get in Class-Entity-Attribute-Value hell like wp_meta. or MediaWiki's page properties. And it's not like they have register globals on; scream off; error_reporting 0; allow_url_fopen on; allow_url_popen on like the last PHP project I saw... right?


  • Grade A Premium Asshole

    @TwelveBaud said:

    Although I do see the WTF here, I can't help but wonder how much worse it could have been. You can see exactly when a client was onboarded, which changes to trunk were made that have or have not made it into the client's code, and who to blame when something goes wrong -- things that are much more difficult with 600 folders. And having one unified DB schema would certainly make migrating changes easier, but then you get in Class-Entity-Attribute-Value hell like wp_meta. or MediaWiki's page properties. And it's not like they have register globals on; scream off; error_reporting 0; allow_url_fopen on; allow_url_popen on like the last PHP project I saw... right?

    Really? This is like someone building a drone, putting thermonuclear weapons on it, tying the detonators and navigation system to a random number generator and then your statement is, "Well...at least it won't be harmful to the entire universe."


  • Notification Spam Recipient

    @loopback0 said:

    @DogsB said:
    Maybe I'm just odd but I kind of want this job....

    Yes.

    @loopback0 said:

    @DogsB said:
    Maybe I'm just odd but I kind of want this job....

    Yes.

    Maybe not the php bit. Also, your new avatar is adoreable!



  • the WTF is clear. they should've used a forking workflow instead of a branch based one


  • area_pol

    The developers recognized that their architecture is flawed, sought help and having received the replies, acknowledged that they need to make the application modular.
    With a good attitude the technical difficulties can be overcome.


  • Discourse touched me in a no-no place

    @Jarry said:

    forking workflow

    :giggity:



  • I've been through all the different variations of making a PHP application easily customizable for different sorts of customer projects and the best one has been a combination of:

    1. make small things configurable (configuration files)
    2. make bigger things extendable (extending classes)
    3. make everything overridable (rewriting complete modules)

    While the last of the three is quite intrusive, it makes some customization possible that just must be done at one point in time but aren't "upstreamable" to other customers in the core code. Making it too hard or impossible will just bite you back when you need to get shit done but your crappy product doesn't allow you to.

    Also there's no need to branch/fork anything when the core code and customer code are in separate repositories and they are joined together in release/build process.


  • Winner of the 2016 Presidential Election Banned


  • Winner of the 2016 Presidential Election Banned

    @DogsB said:

    Also, your new avatar is adoreable!

    Ah, yes, finally, something we can agree on.


  • Notification Spam Recipient

    @Fox said:

    @DogsB said:
    Also, your new avatar is adoreable!

    Ah, yes, finally, something we can agree on.

    Ah yes. SJWs always hold a grudge. 🙋 🙋🙋🙋🙋

    I see a jeff in our future!


  • BINNED

    @hifi said:

    While the last of the three is quite intrusive, it makes some customization possible that just must be done at one point in time but aren't "upstreamable" to other customers in the core code.

    I handle that by making everything protected and handling stuff through __call. It's a bit hacky, yes, but it helps with getting around PHP's overriding being a bit wonky. Also, I'm doing DI so I have to do some weird stuff on that front. Out of interest, what's your approach? Regular overriding or something more fancy?



  • Regular overriding with empty classes that can be overridden in customer code via include path order and base classes that have the actual code.

    I can't take the credit for this pattern but I do like it because it makes all other hacks seem clumsy.

    And yes, always protected instead of private. Every time something has been declared private it needs to be extended in one month.



  • @Onyx said:

    I handle that by making everything protected and handling stuff through __call. It's a bit hacky, yes, but it helps with getting around PHP's overriding being a bit wonky. Also, I'm doing DI so I have to do some weird stuff on that front

    :wtf: if you have DI, why do you have to do __call inchantations?
    you rolled your own IOC?


  • BINNED

    Kind of, yes. If you have any resources on how to do it "properly" in PHP I'm all eyes, I found nothing of much use myself. Not sure if I used the wrong search terms or something, but I did feel a bit like reinventing the wheel because I couldn't find any blueprints of the original at times.



  • uhm, here we drink the laravel kool-aid. so we use laravel service providers.
    for a simpler approach:

    is nice and simple. it mostly Just Workstm

    this is a good starting point for a more broad investigation:

    altough this is not the complete thing. it varies depending of your actual architecture.


  • BINNED

    Well, I don't think I'll be changing much at this point but you know, contrast and compare, maybe I see some bits that will help me smooth over some bumps in the design.

    Thanks for the links.



  • 🙇

    if you want, we can start a new thread to compare approachs.



  • @Onyx said:

    @WernerCD said:
    The Real WTF is PHP

    Nope, sorry, not this time. It's perfectly possible to write modular code in PHP. You can even do decent enough dependency injection if you're slightly clever about it.

    This time, TRWTF is devs. Sorry.

    But can you write perfectly cromulent code in PHP?


  • BINNED

    @Arantor said:

    But can you write perfectly cromulent code in PHP?

    <?php
    

    There you go. That takes you half of the way there.



  • I read "customization for different purposes, each in a separate branch" and instantly knew the problem. Neither PHP nor git can be blamed for this monstrosity. If anything, git alleviates some of the pain because branching is cheap...



  • @WernerCD said:

    Customers each have their own branch in the version control system.

    Ha! I used to work at a place with that setup. Except they weren't branches because they weren't in source control, they were just copy-pasted directories on someone's hard drive. And there weren't that many copies, they just overwrote the code for Customer 4 with the code for Customer 5. And they didn't have a baseline version so code specific to Customer 4 stayed in the code base for Customer 5, including the name and logo of the previous customer showing up on the site for the newer customer in some places.

    First week on the job I asked: "where's the code for Customer 4?" and they said "we don't have it anymore".

    Mind. Blown.

    I ended up de-compiling the code in production and checking that in.



  • been a single programmer maintaining something similar, except with only about 60 customers (most of which I didn't know existed until they needed some changes), and no version control or testing servers, just logging into their production servers and making the changes on live versions of the sites.



  • @WernerCD said:

    500 clients who are subscribers of our software, ... each in a separate branch.

    @Bort said:

    I ended up de-compiling the code in production and checking that in.

    @sh_code said:

    something similar, except with only about 60 customers

    This much is obvious to me: :doing_it_wrong: :facepalm: :headdesk: :headdesk: :headdesk:

    But, asking as a version control dummy. If we have a lot of customers and code customization is required for each, what is the proper way of doing this?



  • Do your customers have access to the source code? If not, I'd store them all in the same tree and compile with whatever your language's equivalent of build tags is.



  • @Onyx said:

    making them all work together is like herding cats

    You mean like this?
    http://www.youtube.com/watch?v=Pk7yqlTMvp8
    So, perfectly manageable.



  • no idea. I've never seen or heard of such case being handled in any way
    that sounded sane. My instinctive solution would be "give the customer
    price quote so high that they either drop their silly change requests, or
    basically pay for a whole separate team to dev and support just their
    version".

    2015-11-10 7:44 GMT+01:00 One polygon Four-sided <
    use-the-contact-form@thedailywtf.com>:


  • kills Dumbledore

    @CoyneTheDup said:

    If we have a lot of customers and code customization is required for each, what is the proper way of doing this?

    One common one I see is to have each feature available to all clients and controlled by a features and options table in the database. Then all the branching is in the one code base and nobody has ever tested all the possible permutations of options and features. This also ensures that you can charge for multiple days of a consultant installing the software for each new customer.



  • I haven't dealt with the problem myself (having 600+ customers in a single application... good problem to have in many aspects), but from the description of the problem - which is rather light honestly... Solutions like this - features, with "are you enabled?" logic in the application for each client sound like a good option. Modules are another approach I'd try. Many other good options make appearances in the answers part of the question...

    I'd also work towards having text in consolidated locations - text files or database tables (one of the "changes" per customer was different field names or text descriptions) which would also work towards i18n.

    I just can't fathom having a branch per customer (or a folder copied per customer as others have mentioned here)...

    I've always tried to live with doing something once is perfectly... repeating it twice is okay... doing the same thing three times means its time to refactor and pull the common stuff out into a common location. Not doing something before 600... shiver


  • Java Dev

    Before I joined this employer, they used a solution-based approach where the toolkit was the same everywhere and version-controlled, but the business ruling (a turing-complete language in its own right) and definitions of datasets, columns, etc. varied for each customer and typically were version-controlled at the customer only or not at all. Toolkit upgrades didn't happen.

    I didn't catch much of it, since 6 months after I started was the acquisition and the full move to a product model. Though we've still got configuration-defined datasets, columns, and a turing-complete business rules engine.



  • @Jaloopa said:

    One common one I see is to have each feature available to all clients and controlled by a features and options table in the database. Then all the branching is in the one code base and nobody has ever tested all the possible permutations of options and features. This also ensures that you can charge for multiple days of a consultant installing the software for each new customer.

    That's what we do as well. But Alex wrote an article (Soft Coding) describing that practice as a :wtf:. Not that I necessarily agree with what he said...he didn't have to deal with our 30 customers, much less 600.

    This company used what appears to be a...well, a :wtf: strategy. I was just exploring options: If one were doing individual source for each company, what would be an appropriate strategy? Could happen, right?

    And, yes, soft configuration can be expensive, unless you have a client already close to what you want that can be cloned.



  • As has been mentioned, storing options in a database (or configuration file) is probably the best way to do it. If that isn't possible for some reason, you could try storing customer-specific changes as diffs that you can apply to the base source code. That would still be WTFy, but it might be somewhat less WTFy than trying to maintain complete branches for each customer.


  • Notification Spam Recipient

    @Dragnslcr said:

    If that isn't possible for some reason, you could try storing customer-specific changes as diffs that you can apply to the base source code. That would still be WTFy, but it might be somewhat less WTFy than trying to maintain complete branches for each customer.
    Considering how cheap branches are in git that sounds just as bad. At least with git you have branching and tagging to help a bit. Then comes where do you store the diffs?

    @Dragnslcr said:

    As has been mentioned, storing options in a database (or configuration file) is probably the best way to do it.
    Yeah, have down stream branches for developing new features specifically for clients but eventually generalize them, hopfully make them configuration driven, and then merge the feature back upstream. Hopfully you can sell the feature to existing clients as an added bonus.

    To be honest we don't have the full picture. The clients could just be too different and a plugin architecture over different repositories might be the way to go.


  • Discourse touched me in a no-no place

    @Dragnslcr said:

    If that isn't possible for some reason, you could try storing customer-specific changes as diffs that you can apply to the base source code.

    What do you think that maintaining a customer-specific branch is equivalent to otherwise? (Ideally, the places where the branch adds in changes should be pretty small in number and designed to have such changes applied to the code at that point…)



  • My initial thought was that it would be slightly easier to maintain, since you wouldn't have to constantly merge from master to every one of those branches. Instead, you'd only have to update the patches when something changes that interferes with applying the patch. I guess you could have a script do all of the merges as long as there aren't any conflicts.

    I never said it wouldn't be a WTF, I'm only guessing that it might be a slightly less annoying WTF than having a full branch for every customer. I would still avoid having any kind of separate code for different customers if at all possible.



  • @Dragnslcr said:

    My initial thought was that it would be slightly easier to maintain, since you wouldn't have to constantly merge from master to every one of those branches.

    But if there are no conflicts the merges are virtually zero-effort (and yes, with 600 branches you would want to automate it to a single click/command), and if there are conflicts then you need to have the patches account for that anyway.

    So... pretty much exactly like with a VCS, except the VCS would probably be better at detecting the merge conflicts than you.



  • ...some kind of dependency injection use, now that I think about it? having variations that are un-configurable (those that are more than just localization things, basically) as separate (sub)classes, one for each customer, then versioning just the classes?
    partly inspired by another job where one finance app (a huge pile of wtf, main business app of basically bank-like company, handling all the billing and finance computations, written in PHP) had per-country variants of most of the business logic classes, because billing and interests computations were so different due to different laws in the countries. In the case of this app, however, all the code was present in everyone's package, and app decided which specific classes/files to include based on a "country" config setting.

    opinions and reactions on this are welcome.



  • @Jaloopa said:

    One common one I see is to have each feature available to all clients and controlled by a features and options table in the database. Then all the branching is in the one code base and nobody has ever tested all the possible permutations of options and features. This also ensures that you can charge for multiple days of a consultant installing the software for each new customer.

    This is what we do


  • kills Dumbledore

    It started as a fairly serious "this is a decent method I've seen" post, then I kept remembering the shitty ways my company does it and it made me sad



  • More accurately, it's what we're trying to do. We still have half a dozen mutant versions of the codebase that can't be merged to the current one at present.


Log in to reply