There has been a lot of hype around microservices over the last couple of years. I've been doing a fair bit of research and experimentation with this architecture and think it is the perfect fit for certain large project but needs to be adopted with very careful consideration.
The positives are undeniable, having independently deploy-able, language agnostic services that can be tested in isolation definitely has the potential to scale well. This will also add much needed flexibility that is lacking in many complex systems.
However for many projects this architecture will introduce significant real world challenges including:
Code Reuse: When I started looking into Microservices the following question kept coming up "Where should I draw the line between having shared class libraries vs moving common code into a new shared services?"
Shared class libraries are frowned upon by many purists because it goes against the independence paradigm of microservices and will thus reduce some of the benefits of having services that are truly decoupled . However not having a shared class library is likely to result in significant refactoring of code when logic that should of been shared is moved from one service to another. This has the potential to be expensive and may result in many other interdependent services being affected. Obviously this kind of problem exists with non-microservice architectures however changing a class library, compiling and then fixing every compilation error as well as using built in refactoring functionality in IDE's such as Visual Studio is likely to be easier than refactoring services across a varied technology stack and having to rely on excellent unit test coverage to ensure everything is picked up.
As is often the cases with tight deadlines and limited budgets there will be cases where moving common code into a new service becomes too costly and/or risky and developers will end up redundantly replicating code which breaks the DRY design principle and will reduce the overall maintainability of the system.
Debugging: It is likely to add complexity to debugging when a developer needs to step through code across independent, queued, services calls through logic that is implemented in a variety of technologies.
Language Agnostic: One of the commonly spruiked advantages of microservices is that they are language agnostic. However without careful consideration this can lead to the creation of a very complex technology stack. This may make maintainability an issue because software currency upgrades and patches will become more complex and because finding experts who have experience with a varied technology stack become more difficult to find.
Version and Deployment Control: This one is pretty obvious. It can be difficult enough trying enforce consistent and understandable version numbering accross an n-tiered application. Try having hundreds of services and multiple persistence repositories and this can get very confusing and difficult to control.
Refactoring: Undoubtedly deciding when to create a new service, merge two or more services, or split existing services into multiple services will be a relatively common occurrence. This will have a cost because merging or splitting services could result in hundreds of services and potentially thousands of test cases being significantly affected.
So in summary, microservices architecture certainly has some advantages but it will work best when some very careful guidelines and standards are put in place across a project team to address some of the issues I've detailed above.