I’ve been having a discussion lately with some colleagues about the best way to approach a new project, and thought it’d be interesting to get some external thoughts thrown into the mix.
Basically, we’re redeveloping a fairly large site (written in PHP) and have differing opinions on how the platform should be setup.
Requirements:
The platform will need to support multiple internal websites, as well as external (non-PHP) projects which at the moment consist of a mobile app and a toolbar. We have no plans/need in the foreseeable future to open up an API externally (for use in products other than our own).
My opinion:
We should have a library of well documented native model classes which can be shared between projects. These models will represent everything in our database and can take advantage of object orientated features such as inheritance, traits, magic methods, etc. etc. As well as employing ORM.
We can then add an API layer on top of these models which can basically accept requests and route them to the appropriate methods, translating the response so that it can be used platform independently. This routing for each method can be setup as and when it’s required.
Their opinion:
We should have a single HTTP API which is used by all projects (internal PHP ones or otherwise).
My thoughts:
To me, there are a number of issues with using the sole HTTP API approach:
-
It will be very expensive performance wise. One page request will result in several additional http requests (which although local, are still ones that Apache will need to handle).
-
You’ll lose all of the best features PHP has for OO development. From simple inheritance, to employing the likes of ORM which can save you writing a lot of code.
-
For internal projects, the actual process makes me cringe. To get a users name, for example, a request would go out of our box, over the LAN, back in, then run through a script which calls a method, JSON encodes the output and feeds that back. That would then need to be JSON decoded, and be presented as an array ready to use.
-
Working with arrays, as appose to objects, makes me sad in a modern PHP framework.
Their thoughts (and my responses):
-
Having one method of doing thing keeps things simple. – You’d only do things differently if you were using a different language anyway.
-
It will become robust. – Seeing as the API will run off the library of models, I think my option would be just as robust.
What do you think?
I’d be really interested to hear the thoughts of others on this, especially as opinions on both sides are not founded on any past experience.
1
Your approach looks like the way to go. A single HTTP API isn’t that simple if you need to be making http requests all the time.
Features like “good documentation” and ORM will be a necessity when the project becomes larger.
It will be very expensive performance wise. One page request will
result in several additional http requests (which although local, are
still ones that Apache will need to handle).
For internal calls, I agree, but not all APIs are RESTful, and not all do simple CRUD work (though that’s the most common use-case for them).
You’ll lose all of the best features PHP has for OO development. From
simple inheritance, to employing the likes of ORM which can save you
writing a lot of code.
Why? You can still use all of those things in an API. Where do you think the API server gets its data? An API doesn’t necessarily access a database directly. It almost sounds as if you’re only looking at this from the API consumer’s point of view. Even that’s flawed, really, because what the consumer gets can be one or more objects, too.
In an MVC architecture, an API isn’t much different than any other MVC application. You have your views – the JSON response. You have your Controllers, and your Models. You get all of the same benefits of OOP available to you. The only major difference is how you’re presenting the data (and possibly, how much data you’re presenting at a time).
For internal projects, the actual process makes me cringe. To get a
users name, for example, a request would go out of our box, over the
LAN, back in, then run through a script which calls a method, JSON
encodes the output and feeds that back. That would then need to be
JSON decoded, and be presented as an array ready to use.
When communicating between languages, you have to convert to something that everything else understands. In most modern software systems, this is JSON. When communicating between applications of the same language, then you have a choice of either libraries or again communicating in JSON.
Working with arrays, as appose to objects, makes me sad in a modern
PHP framework.
Who says you have to work with arrays with PHP’s JSON methods? json_decode
converts to an object by default (if you want an array, you have to set the assoc
flag), and if you don’t have a framework that already does it, you can write a helper function “to_json” function that converts a PHP object to an associative array. Or, if you’re using 5.4 or greater, you can implement JsonSerializable
to convert the object to be encoded.
You mentioned that one of your plans was to write a mobile application and a toolbar that will access this new system. If you don’t have an API, then how do you plan to communicate with those offsite applications? You don’t want either of those interfaces to store everything and do some of the really heavy lifting of your application, so at some point, you’re going to need to have an API anyway.
As for your internal applications, it largely depends on the exact implementations of what you already have. If you’re dealing with a number of different languages, then going your route means you have to maintain that many different code bases for the same thing. Whereas, if you go the API route for them, too, you have a single codebase to maintain, at the cost of having to connect to it as though they were external entities (which can be very small, if you build it right; think about how many APIs you likely already use, and how seamless most of them are). Keep in mind, too, that the API route allows you to move those other applications off-site should the need ever arise. Going the library route likely means a major code change is in store if you need to move it offsite.
Well, basically you are right. Your arguments are valid and really heavyweight.
But they are right, too. It’s simple and robust. It’s decoupled. A HTTP api is the way to go, if you ask me.
There would be a third way. What keeps you from implementing HTTP api in PHP? This way you can reuse everything.
Here’s how I’d do it: Having the HTTP api, you can abstract it in your application. There will be no difference to a model using the database directly or the HTTP api. After all, it’s CRUD either way. It will be slower, yes. But if it runs on the same box, it won’t be a show stopper, because request will never leave your machine. JSON encoding and decoding is pretty fast too.
In the HTTP api I’d go for Java, using JPA and JAX-RS. This way it’s pretty straightforward.
-
Local HTTP requests are cheap, performance-wise cost almost nothing when you have keepalive. If you want it to be faster you can use persistent sockets with gzencode instead.
-
ORM is usually spitting out horrible SQL code, which is sub-optimal and this is the thing that will lower your performance a lot. An anti-pattern. And you actually want to share these models across the project? One small schema change in one of the projects will need to be included in every of them… it’ll be maintenance disaster.
Best feature in a project is having it built using small de-coupled sub-systems, not one large pile of crap that is tightly integrated and no one can fully understand.
The sad thing is that people are translating beautiful relational code, into something as shitty, unreadable and slow as automatically generated PHP classes, with gazillion od stupid methods, filters, constants and table shema in bloated XML’s and in the end you write half of your SQL manually because it can barely manage to properly do simple inserts, most trivial updates, and selects with JOIN anyway.
Actually can this ORM support something as “complicated” as multi-insert without transaction or simple SELECT FOR UPDATE nowdays? When i checked doctrine / propel last time, all i got for most simple things was just stupid excuses and the supported feature set was so primitive that i could probably use mysql from 10 years ago and I wouldn’t notice.
ORM in 2016, when DB vendors are inventing new features like crazy and you want to settle for a DB code from a stone age? Come on.