4 ms·
Not specifically about event-driven, but the most damaging anti-pattern I would say is microservices. In pretty much all projects I worked with in recent years
by onetimeuse92304 2y ago
Not specifically about event-driven, but the most damaging anti-pattern I would say is microservices.
In pretty much all projects I worked with in recent years, people chop up the functionality into small separate services and have the events be serialised, sent over the network and deserialised on the other side.
This typically causes enormous waste of efficiency and consequently causes applications to be much more complex than they need to be.
I have many times worked with apps which occupied huge server farms when in reality the business logic would be fine to run on a single node if just structured correctly.
Add to that the amount of technology developers need to learn when they join the project or the amount of complexity they have to grasp to be able to be productive. Or the overhead of introducing a change to a complex project.
And the funniest of all, people spending significant portion of the project resources trying to improve the performance of a collection of slow nanoservices without ever realising that the main culprit is that the event processing spends 99.9% of the time being serialised, deserialised, in various buffers or somewhere in transit which could be easily avoided if the communication was a simple function call.
Now, I am not saying microservices is a useless pattern. But it is so abused that it might just as well be. I think most projects would be happier if the people simply never heard about the concept of microservices and instead spent some time trying to figure how to build a correctly modularised monolithic application first, before they needed to find something more complex.
- roncesvalles 2y agoAlso, the single most nonsensical reason that people give for doing microservices is that "it allows you to scale parts of the application separately". Why the fuck do you need to do that? Do you scale every API endpoint separately based on the load that it gets? No, of course not. You scale until the hot parts have manageable load and the cold parts will just tag along at no cost. The only time this argument makes sense is if one part is a stateless application and the other part is a database or cache cluster. Microservices make sense when there are very strong organizational boundaries between the parts (you'd have to reinterview to move from one team to the other), or if there are technical reasons why two parts of the code cannot share the same runtime environment (such as being written in different languages), and a few other less common reasons.
- onetimeuse92304 2y agoOh, it is even worse. The MAIN reason for microservices was that you could have multiple teams work on their services independently from each other. Because coordinating work of multiple teams on a single huge monolithic application is a very complex problem and has a lot of overhead. But, in many companies the development of microservices/agile teams is actually synchronised between multiple teams. They would typically have common release schedule, want to deliver larger features across multitude of services all at the same time, etc. Effectively making the task way more complex than it would be with a monolithic application
- withinboredom 2y agoI've worked with thousands of other employees on a single monolithic codebase, which was delivered continuously. There was no complex overhead. The process went something like this: 1. write code 2. get code review from my team (and/or the team whose code I was touching) 3. address feedback 4. on sign-off, merge and release code to production 5. monitor logs/alerts for increase in errors In reality, even with thousands of developers, you don't have thousands of merges per day, it was more like 30-50 PRs being merged per day and on a multi-million line codebase, most PR's were never anywhere near each other.
- Supermancho 2y agoRegarding monoliths...when there's an issue, now everyone who made a PR is subject to forensics to try to identify cause. I rather make a separate app that is infrequently changed, resulting in less faults and shorter investigations. Being on the hook to try to figure out when someone breaks "related" to my team's code, is also a waste of developer time. There is a middle ground for optimizing developer time, but putting everything in the same app is absurd, regardless of how much money it makes.
- withinboredom 2y agoI'm not sure how you think microservices gets around that (it doesn't!). We didn't play a blame game though... your team was responsible for your slice of the world and that was it. Anyone could open a PR to your code and you could open a PR to anyone else's code. It was a pretty rare event unless you were working pretty deep in the stack (aka, merging framework upgrades from open source) or needing new API's in someone else's stuff.
- SadCordDrone 2y agoAlso - you give up type safety and refactoring. LoL
- onetimeuse92304 2y agoWell, technically, you can construct the microservices preserving type safety. You can have an interface with two implementations - on the service provider, the implementation provides the actual functionality, - on the client, the implementation of the interface is just a stub connecting to the actual service provider. Thus you can sort of provide separation of services as an implementation detail. However in practice very few projects elect to do this.
- sophiabits 2y agoEven with this setup in place you need a heightened level of caution relative to a monolith. In a monolith I can refactor function signatures however I desire because the whole service is an atomically deployed unit. Once you have two independently deployed components that goes out the window and you now need to be a lot more mindful when introducing breaking changes to an endpoint’s types
- Pet_Ant 2y agoYou don't have to. The producers of the microservice also produces an adapter. The adapter looks like a regular local service, but it implements the code as a REST request to another microservice. This was you get you type-safety. Generally you structure the code as Proj: |-proj-api |-proj-client |-proj-service Both proj-client and proj-service consume/depend-on proj-api so they are in sync of what is going on. Now, you can switch the implementation of the service to gRPC if you wanted with full source compatibility. Or move it locally.