
API-first architecture, or the fat vs. thin server debate - maus80
http://www.leaseweblabs.com/2013/10/api-first-architecture-fat-vs-thin-server-debate/
======
jacques_chester
I remember when this sort of thing used to be called SOA. Before that there
was n-tier, before that client-server, before that people used to talk about
terminals.

    
    
        What has been will be again,
        what has been done will be done again;
        there is nothing new under the sun.
    

The best place to park different parts of the logic varies according to the
algo-economics of the day. Right now people have fast client environments, so
the balance is tipping back to heavy clients.

~~~
1qaz2wsx3edc
SOA (Service-oriented architecture) is a pattern to split an application into
discrete pieces of software providing application functionality as services to
other applications.

Fat vs Thin is more over a debate about where to place logic. Thin implies
controllers are small, and models have a wider responsibility. Fat is the
inverse, where controller do the majority of work, and models are a small
abstraction.

My point is this: They are not the same thing. SOA helps in designing
scalable, robust systems. Fat vs Thin helps you decide where logic should go.

I'm proponent of SO design and thin controllers.

~~~
PaulHoule
Well, unless you design them for high performance from the very beginning, SOA
also helps in building slow systems that your customers will hate and that
will fail in the marketplace if the people who buy the software actually use
it.

(I was at Altassian's San Francisco office a few months ago and I said half-
jokingly that I quit my last job because I couldn't stand waiting for
Confluence, and all the other off-brand webapps my employer used, to load.)

Now I use Github, which offers true interactive performance even over crappy
DSL connections. I'm not going to work for anybody who makes me use some off-
brand webapp that makes me wait 30 seconds to put time on a ticket or to edit
a Wiki page.

SOA can be part of the solution rather than the problem, but it takes a clear
architectural view from day one and a commitment to avoid stupid and obvious
mistakes, as the article points out.

~~~
Gigablah
Not sure why you're blaming SOA there. Atlassian apps are standalone instances
so, assuming your former employer self-hosts, it has more to do with your own
server and network performance.

In fact GitHub is most likely closer to SOA architecture than Confluence is.

~~~
PaulHoule
They weren't self-hosting.

And whether it is SOA or not, the moral is that many many systems are designed
and sold as if performance didn't matter.

I had another job where the team toiled for years to develop an SOA system
that, when we first stacked it all up, took 45 minutes to boot up an RIA
because it did 50,000 requests to initialize it's state.

Sure, this is stupid design, but people do this all the time.

I was able to speed the boot time to 20 seconds by packing much of the data
with the application file and creating one "initialize" call that downloaded
all of the data necessary to initialize a particular instance of he app in one
shot.

Had performance been built into the app from day one that app might have seen
the light of day.

------
NathanKP
One massive advantage of the API first architecture that wasn't mentioned in
this article is that it makes proper unit testing much easier because of the
clear distinction between the server side API code and the client side
JavaScript/Mobile app.

Of course it is possible to test a "fat" server that does view and
presentation logic, but it is much easier and more efficient to test a thin
server and have a separate suite of tests for the client side app.

~~~
PLejeck
I've always been curious how people do integration tests on things with
multiple servers (like SOA stuff), it seems like it'd be dreadful, unless you
use Vagrant to (quite slowly) spawn a new VM every time you want to test.

Anyone with experience care to enlighten me?

~~~
tunesmith
I've used mocking for this purpose. Not in the same way you would for unit
testing, of course. But if you want to integration test the (entire) workings
of a consumer of a service, then your test starts with its entry point
(whether a form submission, an API request, or whatever). Then if part of your
consumer's business logic relies on a call to an external SOA service, you
mock that service. In other words you say, "Given this particular form of
request that would be sent to the SOA service, respond with this particular
service response". Then your consumer will continue on with its business
logic, all the way up until it returns its response to your original request,
and you can apply your assertions then.

It's not a true end-to-end test, which would require all your services to be
up, but it is an integration test since it tests the entire workings of the
consumer. The assumption is that other test suites would test each of the
services, and maybe a ping test to test the availability of the services
themselves.

~~~
PLejeck
I've never been able to fully grasp mocking and stubbing.

~~~
tunesmith
The most common objection I've heard to mocking is along the lines of, "If
you're mocking, what is the point of the test?" The answer lies in having a
clear understanding of what you are testing.

For instance, method A might call another class's method B. If you're writing
a unit test for method A, you don't also want to test method B. (Other unit
tests would test B in isolation, instead.) So in A's test, you make A call a
mock B rather than the real B, and you ensure B returns a particular kind of
response. In other words, you want to make sure method A behaves correctly
when it gets certain responses from B.

So in english, a test is basically saying, "When B gives this type of response
(which I'm forcing it to respond with), make sure A behaves as I expect", and
a second test says, "When B gives this _other_ type of response (which I'm
forcing it to respond with), make sure A behaves as I expect.

So when you write a unit test for A, you mock B by making it send back a
canned response and make A use it. Then you call A with some parameters, and
then you make sure that A's return type is as you expect.

One advantage of this is that if a future code enhancement breaks one of the
methods deep in the code, then the failing unit test will tell you exactly
where the problem is. Without mocking, a failed unit test will make you have
to examine several layers of stack trace to find the bug.

~~~
justincormack
Also getting the right kind of response out of a back end server may be hard,
eg getting certain kinds of error or unusual responses, so mocking is the only
way to get them reliably.

They are not a substitute for end to end tests though, as you cannot tell if
some other assumption is broken.

------
joshfraser
One of the biggest benefits I see to API-first is that it encourages you to
document everything well, and that process usually leads to better
organization and greater consistency.

As far as fat vs. thin, I worry that this article could be a bit misleading.
It's great if you have an API that responds in 20ms as very few people can
achieve that. But it doesn't matter much in a world where mobile network
latency can easily be 200-500ms. If you're worried about app performance, I'd
focus first and foremost on the number of requests you are making and making
sure none of them are blocking. The network is the slow part. I know a lot of
companies with blazing fast API's and sluggish apps, because they're
optimizing the wrong thing.

~~~
PLejeck
When developing an API, I like to practice "documentation-oriented design."
The first thing I do is write documentation of the API, and then I write APIs
to fit that documentation (iterating both in parallel once I start writing the
API).

I figure that the documentation is the first thing a developer faces when
using an API, so it should also be the first thing I write.

~~~
dreamfactory
A related approach is client-driven development (just made it up). Write
client code (or controller) in the most thin, elegant, and obvious brain-dead
simple way, then build an API (or model) to service it.

~~~
PLejeck
It's okay, I totally just made up "documentation-driven development" too. And
yeah, that's the best way I find. Always build a consumer and then build the
supplier, you'll usually end up with a great experience.

------
PLejeck
The article makes the implication that MVC is inherently slow. It's not, in
fact it can be quite fast if you use the right framework.

I'm assuming they only know that Rails is slow (which it can be, especially
for a case where caching can't help much like in an API) and assume that's
because of MVC and not because Rails is monolithic and Ruby-based.

Before I used Rails, I used an MVC consisting of Mongoose + Handlebars +
Express in Node.js, and I regularly had pages render in under 10ms. The
biggest bottleneck was consistently the communication with MongoDB, something
I had very little control over.

So to conclude, stop blaming the architecture, start blaming the frameworks.

~~~
meowface
>The biggest bottleneck was consistently the communication with MongoDB,
something I had very little control over.

Interesting you say that, because one of Mongo's few redeeming features is
that it's supposed to be pretty fast for both reading and writing. Exactly
which part was the bottleneck? Was your app more read-heavy or write-heavy?

~~~
PLejeck
The problem I ran into was that I needed to perform roughly 20 interdependent
queries in a short period of time. At most, I could do 5 queries in parallel
due to the interdependent nature, but I still ran into trouble with the
database being slow.

In the end, I added Redis as a caching layer, which cut time-per-query down a
few ms per request, which was significant in this case.

I can only imagine how bad it could've been if I had block for each request
instead of using the asynchronicity of node.

~~~
meowface
Right, caching is usually the easiest way to solve problems in those
situations.

>I can only imagine how bad it could've been if I had block for each request
instead of using the asynchronicity of node.

All modern web servers/frameworks are going to be asynchronous in one way or
another, whether they spawn a new thread or process for each request (and for
each database query), or whether they use polling and an event loop like Node.
Node and HTTP servers like it are only a boon when you expect to have so many
concurrent requests that threads/processes will begin to hog too many
resources.

So unless your server was really being hammered with queries for hundreds or
thousands of concurrent users every second, I imagine using Node was neither a
significant advantage or disadvantage. And if it's the database or database
driver that can't handle concurrency, then Node would do absolutely nothing to
help there.

------
pearjuice
Please note that the thin server should never be too thin. Logic should always
happen in the server domain, handle the client as merely a presentation unit.

~~~
yeukhon
Not all logic. You can do simple input verification on client side. You can do
in pace filter and yielding from client side. Bu anything tht requires
extracting db and saving o db must go bough server side to ensure security is
met.

~~~
sjwright
Input verification and pace filtering must be duplicated on the server side as
well. You can do this on the client side _as well,_ but only to aid good user
interaction, not to actually verify input.

~~~
yeukhon
hence why i said anything that has to go through db and save to db has to go
through server.

~~~
joesb
Which is the point of pearjuice's post about the logic not being _too_ thin.
Also _duplicating_ same verification logic on _both_ client and server does
not make the _server_ thinner, it only makes the _client_ fatter.

------
AYBABTME
This article suggest that MVC implies a fat server, and that using newer
patterns with thin servers breaks away from MVC.

Using a thin server with a Javascript heavy app basically means keeping the
Model/Controller on the server, then having Views/Controllers on the client.

So in the end, you're still with a MVC pattern, you just spread your
Controller over two machines with RPC in between.

~~~
dreamfactory
To me a controller is just another thin client and models provide an
(internal) API. What breaks this and leads to fat clunking controllers is
ActiveRecord and 'model as table row' mindset (particularly when a model
doesn't handle collections).

The missing part here is turning that API into an external one, which requires
a layer in any case to cover things like authorisation, caching, queuing,
reporting, QoS, orchestration.

------
ubersoldat2k7
In my last three projects we've aimed at an API first approach, and the
flexibility of having the same API serve content for web or native mobile apps
is the biggest win. We used Play on two of this projects and Jersey for
another and the speed is very slow at first since the browser has to load a
bunch of JS (AngularJS in this case) but then, the whole user experience is
seamless. Our biggest problem with this approach were localization and
authentication/session handling. Tackling this problems were hard at first and
I've never felt confident about the solutions we did for them, specially for
authentication.

------
jamesmccann
This is a good description of the difference between available architectures,
but more detail is probably required to backup some of the discussion points,
beyond the fact that reducing presentation is beneficial for response times.
An API server is still required to render JSON responses?

------
tunesmith
A problem in general is that all these terms are highly overloaded.

Models: For some, models are backend structures that are closely related to
database entities. For others, models are data structures that are passed
around closer to the front, or structures that controllers pass to views. Some
also equate models with domains that have behavior as well as state.

Servers/services: These are often used interchangeably when they are really
not. For instance, your API call has to go to a web accessible server, which
might in turn rely on a separate (SOA) service that is not web accessible.

Client: This can mean the browser or mobile device (client/server), but it can
also mean the consumer of a service (client/service). This consumer might also
be sending serialized data structures or page responses to a browser or mobile
device.

Controller: This can refer to the logic in a mobile device that is making
requests and unpacking json requests. Similarly, it can refer to a part of the
javascript in a dynamic frontend that is doing the same. Or, it can also refer
to the application that is _receiving_ the network request (and in turn
invoking business logic in other layers or making service calls to
remote/private services) and then responding with json.

So, imagine a browser or mobile device that makes a request to a remote
"server" and receives a javascript application. The javascript has its own MVC
architecture. Ensuing requests to the remote server will receive json
responses. The js app might unpack the json in the js app's controller, and
repack it into different models (data structures) that get passed to the js
app's views. In turn, the remote "server" could have a controller that receive
the initial request and returns a "view" that is the javascript app, but also
another controller (more accurately a "resource") that would receive the
RESTful requests and respond with json. These controllers/resources could in
turn have a bit of business logic to help them make calls - via REST or SOAP -
to internal/private "services". These services (on different servers) could
have additional business logic to interact with private databases through daos
that act on models (which somewhat-but-not-exactly represent the database
schema because of ORM).

I guess my point is that past a certain point, "fat" versus "thin" doesn't
really capture the essence of the tradeoffs. It's more a series of questions
of what is consuming what, what the consumer shouldn't have, what the consumer
needs, and what the consumer is going to do with it. The big reason
"controllers" (?) are getting "thicker" (?) is because there is a push to make
the consumer-facing front-end more interactive and dynamic. I think that what
the original article is saying is that if you want that, you should do what
you can to return your API data structures (whether json or whatever) in as
direct a fashion as possible, rather than manually constructing them through a
templating technology and a bunch of views that would normally be used to
return html.

But more generally, I'd say that unless you're talking with a team that knows
exactly what you're referring to (from previous discussions), it's best to
just completely define what you mean by
client/service/server/controller/model/etc in each case, because these days,
it seems like everyone is using them differently.

------
nickthemagicman
BUmp

