Microservices and the layers to watch for when architecting your system
infoq.com
infoq.com
Yes. I absolutely agree.
Start with a monolith. Use server-side rendering if possible. Use SQLite instead of [wretched nosql abomination]. API development is a waste of time. The business doesn't give a shit about any of this. Just make it work, then make it "webscale".
Doesn't this lead to an unnecessary increase in complexity without any immediate benefit?
> API development is a waste of time.
Why do you think so? Doesn't a well developed API mitigate, if not eliminate entirely, needless increases in complexity?
Not necessarily. All the major JavaScript frameworks also support server-side rendering, which is used to improve load times and perceived performance.
Developing an API may also be a waste of time when your client-side application is the sole consumer of the server API. This is especially true when people try to build an API that does too much (often seen when building REST-style HTTP APIs) instead of a more usecase-based (or even view-centric) API.
That layer doesn't go away with server-side rendering. It is always there, even if you don't use a REST API. It just gets fused with views.
In fact, I'd argue that this perception that server-side rendering gets rid of that layer is a telltale sign that the project is already plagued with accidental complexity.
> It usually also implies that you don't have build your data model in two different languages ($BE_LANG + JS/TS);
Unless the front-end is written in pure HTML+CSS, this hypothetical simplification doesn't materialize. Also, you can't brush off or ignore the complexity added by templating engines.
> Developing an API may also be a waste of time when your client-side application is the sole consumer of the server API.
I don't get what point you're trying to make. Even if you are the only client for that API, don't you still need to put it together and maintain it?
But that can be "good enough" for many applications - look at how the site we are discussing this on works as an example....
I disagree. If you expect any type of non-trivial user interaction from the front-end, you'll find most of your needs is not practically possible to implement without javascript running on the client-side.
> look at how the site we are discussing this on works as an example....
Please note that even HN loads javascript, which also makes AJAX calls to the backend.
When I wrote my comment I was actually thinking the same, so I agree with you here. However, I still think the (view) model is way closer to your business model without having to go through JSON (or similar) and without the hassle to ensure the client actually received what it expects. I'd argue it's way easier to change or debug in the general case.
> Unless the front-end is written in pure HTML+CSS, this hypothetical simplification doesn't materialize. Also, you can't brush off or ignore the complexity added by templating engines.
It depends on the application, but of course you will have a few highly interactive parts that needs JS/TS (although technologies like alpine.js/html can help here), but still not all models need to exists in the client.
> I don't get what point you're trying to make. Even if you are the only client for that API, don't you still need to put it together and maintain it?
Yes, I mean "elaborate" APIs, my point being that an API for a single consumer can be entirely focused on that consumer. I've seen a lot of people building very flexible APIs without the flexibility being needed at all. I'd argue that one is not tempted to do that as much when doing server-side rending.
Controller queries DB, builds a Model then passes that Model to a View.
View uses that Model to render HTML which returned to the client.
With dedicated frontend it turns into:
Controller queries DB, builds an API response.
Frontend receives API response and renders it into HTML.
So basically Model is API.
Issue with SSR is that it's not popular nowadays and most frameworks are stagnating. At this point it's better to stick to separate backend/frontend unless you don't want to touch it.
You don't have to build JSON Schema, OpenAPI and whatnot. Just spew some JSON and consume it with JavaScript.
It certainly stagnated a bit in the past, but Rails is still alive and so are newcomers like Phoenix (especially LiveView) or even some new PHP stuff.
Also, a lot of talent is wasted when the old backend guys are barred from doing frontend work. They can be crazy efficient with classical server-side approaches.
> You don't have to build JSON Schema, OpenAPI and whatnot. Just spew some JSON and consume it with JavaScript.
This highly depends on the team structure. In projects where a team (or even single developer) works on both the frontend and backend at the same, it may be fine. However, when there is a dedicated frontend and backend team (in my current project we have a dedicated Android team), it makes sense to have some kind of schema (even when not using codegen). Otherwise you will have a lot of communication overhead.
> Developing an API may also be a waste of time when your client-side application is the sole consumer of the server API
i think this is assuming you'd never need a native (ios, android) client no?If you're a big company and are greenfielding a new design, you either need a huge amount of buyin (eg we're going to go heads down for 8 months and come up with a solution) OR you need to build something that provides incrimental improvements along the way. It's really hard for a new greenfield system to compete on features with one with 5 years of features on it.
If you don't have any users, it's far more valuable to demonstrate the business value as early as possible and then build a more scalable solution that's easier for a large team to manage once you've gotten a good chunk of funding.
While you can be careful about round trips with client side rendering, and graphql helps in that regard, it’s easy to create hidden bottlenecks.
Why do you think using server-side rendering leads to an unnecessary increase in complexity without any immediate benefit?
> Doesn't a well developed API mitigate, if not eliminate entirely, needless increases in complexity?
It does when multiple clients consume that API. The point of GP is, I think, that you shouldn't start with the assumption that you will have at some point multiple clients and prepare for it.
where's the line between from scratch and evolved?
Some people try to write game engines from scratch before actually creating their game. Some people learn & adopt complex frontend frameworks before finishing their project’s landing page. Some people start new projects by immediately building all the abstraction layers they think they’ll need during the project before implementing a single useful feature.
I’ve fallen for each of those at least once, and I’ve seen lots of people doing the same. You’re not going to need it. Wait until it makes sense to justify the hidden time & reliability costs. Wait until you actually know what you need.
Once you have reached at least junior level, start learning about how to split the system into subsystems and putting some additional thought into it.
The business doesn't give a shit about the implementation. Very true... that's why they hired you so that you fucking do. Just do your job.
If you want to work in finance, accounting, sales, investor relations, partnerships, business development or whatever, go do that. If you want to work creating software, start caring about how software is created, or at least don't ruin it for people that do.
If you decide to follow a business career path, you will find that they also have to care about their job, have attention to detail and care about good practices and compliance. In fact, that will also be the case for every occupation in every sector.
Like so many fads in our industry microservices solve a problem that giant, famous companies have and are aped by thousands of companies that don’t, and will never, have those problems.
We have to stay mediocre and keep the bar low, to lower the entry barrier to software and depress wages.
You might prefer that they try anyway just to push up your salary a bit more, and I can’t blame you for wanting that, but all of us in this conversation aren’t going to strategically tailor our thoughts to help you achieve that goal.
How is explaining the way to build actual working shit "ruining it" for others? Do you want to live in some fantasy where Netflix's approach to engineering is applicable everywhere? I don't understand what some of you are trying to get out of this, but it sounds suspiciously like you want to have your cake while simultaneously having consumed it.
Before learning about how to split something into multiple parts, you should start by learning about why you would want to do that.
> If you want to work in finance, accounting, sales, investor relations, partnerships, business development or whatever, go do that. If you want to work creating software, start caring about how software is created, or at least don't ruin it for people that do.
Again, before that you should learn about the why. You are writing software for someone. Why? For most people, especially when doing "web stuff", the why is going to be way more important than the how. Carefully crafted software is useless if it doesn't fit what the business wants. Better than that is bad software that still fits the use case. Even better is carefully crafted software that fits the use case.
That is certainly a deliverable a company can use to grow a team of multiple developers and focus on making progress without being constantly interrupted by incidents, defects, downtime as customers roasting and demoralizing customer support representatives and leaving bad reviews online.
Those slow requests in your logs mean a human is looking at a spinning wheel asking why the fuck they bought your software. That is good for the business.
Your product being affected by a security breach is excellent for the business.
Your company infringing licenses because everyone is copying and pasting shit from the Internet is great for the business.
The mythical, romantic image about "business" is just the place where lazy developers run to when they want to stop caring about work.
Real business people want software that does not break everytime a sales person is giving a demo, want a good reputation and do not want to create opportunities for competitors to have a superior product.
Talking about business is not a valid replacement for doing the things that are actually favorable for the business.
> Right, then let's create spaghetti code where everything is coupled together so that no other developer can understand each other's code, with comments in Klingon.
I reject the idea that you need to split your code into services as soon as multiple developers are working on it. I also reject the idea that everyone needs well-encapsulated piece of code to be able to work, with careful comments explaining everything and a great documentation. That's the ideal case, but life is not always ideal. Some code that you will have to work with is not perfect, and you have to understand it and modify it. Deal with it, that's your job. Sometimes the business needs one small feature delivered in a few days, not a month-long refactor to make "clean code".
GQL notoriously performs weaker to REST in this regard.
>When a user navigates to a page on a web app or deep links into a Single Page Application (SPA) or a particular view in a mobile app, the frontend application needs to call the backend service to fetch the data needed to render the view. With RESTful APIs, it is unlikely that a single call will be able to get all the data. Typically, one call is made, then the frontend code iterates through the results of that call and makes more API calls per result item to get all the data needed.
>For example, I don’t want to navigate through multiple screens to review my travel itinerary; I want to see the summary (including flights, car rental, and hotel reservation) all on one screen before I commit to making the purchase.
I disagree.
Sure, sometimes more than one restful call is made for just one page, but the example given, when architectured properly is just a user foreign key relationship to all its children (reservations flights, rentals, etc), which is just a single sql query.
I don't think the author really understand the flexibility of REST and how much it can emulate what GQL has to offer.
If you want specificity in your query fetching, just add query params or put them in the request body
And if it is the case that you really do need resources from different endpoints, what is preventing you to build that single endpoint in REST?
Also, which properties of GQL make it inherently slower than REST ... ? Both are abstract concepts. (Also I'd argue that GQL is REST.)
That feature is not exclusive to GQL.
But the graphql still will fetch that data and just filter what does out, it still has to get that data.
Example is a query like
``` { currentUser { id name todoLists { title items { name } } } } ```
The resolver will likely get the whole user object from the database, then just send name and id. Then when it finished getting the user, it will then query for the todo lists, and then only send the title (even though it got the whole row for each todo list), then after it fetches those lists, it will query for the items. And retrieve the whole rows of each item from the database.
The data the server needed to fetch didn't change, just what the frontend receives. It is still loading and fetching all the data on that query and then graphql filters the results leaving the server.
Also in the above steps, you notice it queries AGAIN after a data set has been retrieve, this causes an N+1 problem.
It is not inherent in the specs or implementation that fixes these. If you want to avoid fetching the whole object you will need custom code, and to avoid N+1 problem, you need batching of data within requests that "caches" or consolidate nested requests like data-loader, and some form of response caching to help with these issues.
Not siding against the tech, just clarifying those cons.
With this query, { currentUser { id name todoLists { title items { name } } } }
It is up to the server how it is implemented.
- The server can fetch all the data for the user, todolist and items from the database in one go and resolve the client query mentioned above. In this case there will be overfetching from the database if the client only requested user information.
The server can also fetch the data in 3 queries
1> First to fetch the user, lets say with id 1. 2> Then get all the todos for the for user id 1. 3> Then get all the items for all the todos in step 2. Batching/Dataloaders.
All these queries can be executed in parallel on the server side. Does this make the server complex? Yes but there is also benefit to this when the user only request currentUser it does not fetch any todolists or items from the database.
Performance is 99% about latency. And, when having this conversation, we are typically talking about I/O-bound latency.
Assume you have a trivial computer system that can only process 1 thing at a time. The number of things you can process per unit time is inversely proportional to the amount of time it takes to process each thing. Adding more threads/cores to the mix does not change this fundamental equation. Many practical business systems have a large component of processing that must occur in a serial fashion.
Think:
Multiple computers: Milliseconds, One computer: Nanoseconds
How much more work can you do if you can finish each unit in 100ns vs 5ms? How would this impact the user experience? Is the reason you cant finish in 100ns because you are doing global illumination on the CPU or because you are waiting for [hipster noSQL solution] to return some packets to your application server?
You haven't supported your position that GraphQL is weaker at all. Everything that I have read, seen and heard is exactly the opposite. GraphQL seems to be the "I will never go back to REST" experience for virtually everybody I know in the field who has used it.
The other issue is that you're fighting the nature of REST itself to make it do more. Sure, you can make any API call take in specific input and send out exactly the output that you need...but REST API guidelines tend to preach exactly the opposite approach. The call should return one thing and if you want more, you need to get it yourself.
I'm open to hearing your perspective on this, but if you're going to make a claim like that you really need to support it.
If we assume that REST serves more requests than GraphQL, but GraphQL is more flexible, that may be a trade off of dev time of the application vs a dev time of the infrastructure. Which would fit with more and more people using orchestration and things like that. That might be a very wrong assumption though.
As far as dev time excluding onboarding time, lets not forget why gql was created - facebook wanted to separate the data responses to their mobile and web platform
first of all, not all organizations are facebook
secondly, especially for smaller to medium sized startups, not all responses need to be separated, and "shaving" off data for an extra endpoint is not difficult in REST.
and I remember graphql's early website where they made the claim saying that you'll need to have some really huge number of endpoints in order to emulate what graphql has to offer, and since then they have taken that down because of how ridiculous that sounded.
In reality and practice, the number of endpoints that you need to "shave", again, especially for small to medium startups, is slim to none.
Isn't this true for all software systems? If anything, microservice architectures just make it easier to re-architect parts of the system, thus lower the bar to actually do the work.
With regards to stuff inside each service, microservices aren't really different from monoliths.
When service calls are involved, I'd argue that microservices make it even simpler to refactor/rewrite modules and entire services. Microservice architectures already impose boundaries between components that help limit the scope of any work, and teams are free to deploy and run in parallel, even in production, any service they wish to update/rewrite/launch. You can control which service is called with a load balancer, and don't bother much with the services you're developing.
Each microservice is owned by a different team, so if you need to change something that touches 2 or more, you need to collaborate with other teams...this adds a lot of overhead. Not to mention that it becomes almost impossible to do real re-architecting: you can't really move data flows or code from one microservice to another. In my experience you're more likely to end up with duplicate flows, duplicate code, just because it's too damn hard to move "class X" from A to B. In a monolith you can and often do those kinds of changes.
It's also easier to have unit tests. It's easier to have integration tests that are still fast and self contained. Sure, you might say that unit tests are easy to write in any scenario but what I mean is maintaining them becomes easier, especially if you're doing Detroit style. It's easier to not break them when doing larger refactorings.
in some organisations the amount of meetings and overhead scales proportionally to the number of network connections in the architecture diagram, so that also suggests replacing external dependencies with in-process function calls wherever possible.
Systems grow from toddlers to old men, so do the businesses. They just evolve and adapt, otherwise they die.
Your body is constantly "refactoring" itself via catabolic processes, and it's also getting of different forms of waste.
My main question was why implement GraphQL BFF layer on top of REST layer. How is this efficient, unless you have legacy REST service that you want expose as GraphQL service. If I am writing a service from scratch why would I create a REST service and then wrap it with GraphQL service?