It's built with php5, uses pretty static file structure, no namespaces but an autoloader. It has around 150 source files. I must say that it was surprisingly easy to get into the code base. The fact that there are no namespaces means class names have been picked carefully, no generic stuff like "dataholder". About half the classes are entirely static and there is still a lot of assoc arrays being passed around while in other places proper classes are used. The front end is just bootstrap with a little bit of additional js and ajax where it makes sense. Still it is really easy navigating the code base and finding the right spot to extend. I hardly ever felt constrained by the project's design, if ever rather by the inconsistencies of php(5) itself. Yes, sometimes it's annoying to implement a dynamic page update via ajax by hand without fancy abstraction, but if you're not building a modern spa it's not that bad and you actually get what's going on.
That other java code base I'm involved with is about 4 years old and really modular and fancy and maven and every time something needs to be added a discussion starts on how to do it, which parts to abstract away in which way, which library or framework might be suited best, and after five trillion years coding might actually start. I might have exaggerated a bit here but that's somehow the feeling I have more and more in modern software development.
Boom. You can stop here. This has nothing to do with PHP or your project.
It's just the previous devs were good professionals. This is why "it's easy to navigate and extend".
Proper naming is one of the most important tell of a code work well done. You got lucky.
But a (good) framework will enforce a reasonable structure that will drive even less skilled professionals in a unperfect but sane direction. It's still possible to take bad decisions, but less often, and the cost of it is reduced.
You did indeed have a more professional set of folks developing that.
I just inherited a small PHP project written 2 years ago:
* no version control * running as root on apache 2.2 in /var/www/html * php 5.5 * about 12 "pages" each with a healthy mix of html/php ('header/footer' are abstracted to external incudes)
the problem with the 12 "pages" is there's around more than double the logic states and I need to add more. there's a bunch of
if($_SESSION['step3done'] && $_SESSION['step3errors']!="") {}
interspersed all over the place. Do I continue the pattern? Or refactor? The previous developer would add 'new' stuff in a matter of a few hours, because they'd just expand on that pattern; it's now unwieldy, and I need to add 'new' stuff, and expectations are "a few hours".
FWIW, it's probably what I'll do, but am migrating code in to version control, adding items in an issue tracker, and documenting my concerns in tickets, a README, and some code comments. It may come across as a bit passive-agressive, but it's not meant to; just trying to keep a history of concerns while also hitting their short deadline.
PHP needs to be upgraded regardless.
It's the difference between flask and django in the Python world.
Beginners tend to go for flask. It seems easier.
But I actually always recommend Django to beginners, and only flask to experts.
Why ?
Well, because I've worked on a lot of code bases with both django and flask, and when you don't have good devs, the result with flask is disastrous. Indeed, flask delegates a lot of decisions to the dev, and as a result, if you don't know what you are doing, the project ends up with bad structure and terrible security.
E.G: django out of the box rotates your session key, provides csrf token, and en entire auth system. But I've worked last year on a flask project that used unsalted md5 password hashes. Their auth backend returned 403 for most errors in the authentication process, even for bugs, with unrelated 3 words messages.
The thing is, if your project is not a success, you don't care. But the goal of a project is being successful, and if it is, less skilled devs will probably have to work on it.
Hell, most projects don't even start with skilled devs. The reason is simple: there are too much demand for tech, and not enough devs. So we do with what we have. I mean, I have companies in the silicon valley paying a lot of money for me to work from my bedroom in France because they can't hire the expert they need around them anymore.
And when I arrive on a new project, guess what happens ? If it's a framework I know, I can start working on it from day one. If it's not, I'll need time to adjust. It's it's custom, I'll need more time, in direct correlation with the skill level of the other devs that worked on it.
Regarding the beauty of DI, let me provide an example of a typical large application. Such an application may need a UserInfo class to model a user's information in the app. This user info class will likely have many dependencies: it needs a way to persist itself to disk, to make network calls for server syncs, and any other ancillary components. As an app component, I don't need to understand any of this. I just add a component to my constructor and I immediately have access to any functionality I may need. Using DI in this way also has a nice side effect: classes can be stateless singletons and still be easily testable with mocks. And the best part is none of this is magical. All of it is governed by a few simple rules.
I pity them
We used to spend 90% of our time determining the right nail to use, the right wood to use it on, and where best to place it, and only 10% of our time on selecting and wielding the hammer. Now we spend 90+% of our time figuring out which GenericAbstractToolFactoryManagerFactoryInterface to invoke and how to properly invoke it a in such a way as to coerce it to ultimately generate something that eventually might generate something else that will hopefully drive some sort of fastener into something in such a way that will possibly hold it together, and the rest debugging why instead it is generating a generator that generates chisels that are chopping away at the foundation.
Yes, that's an exaggeration, but how much so? We are smart people, we do figure out how to use these complex combinations of systems to build functioning (bloated monstrosities of) applications. But are they really reducing technical debt or adding to it?
Are these systems really going to be easier to maintain in a few years when they have 357 dependencies that have each evolved over time (and or been abandoned)? Easier to optimize, when that means modifying what's going on under the hood of those dependencies? Easier to extend, when doing so would lead to conflicts with those dependencies?
I'm predicting that the next wave of discovery and hype in the field will be focused on improving productivity while reducing technical debt by removing the cruft that we're building now and replacing it with something simpler and more to-the-point.