There is:
a requirement to have a key-values pairs storage shared between multiple services
a simple table in DynamoDB
very simple logic of key-value pairs creation
Intuitively I want to put the DynamoDB table behind a REST service that will implement all the simple logic I have. Unfortunately, this means adding a lot of reliability and performance challenges to the solution, since making my service as good, resilient, and performant as DynamoDB isn't easy.
It's been a while now that I think about creating a shared library for the purpose. The library will implement the logic and connect directly to DynamoDB table. I don't anticipate a lot of changes neither in DynamoDB table, nor in logic that will be implemented in the library.
What are the possible pros and cons of both approaches?
A service is simply a packaging and deployment selection for a library. Both are absolutely valid depending on your particular needs.
I'm curious why you feel the need to wrap dynamodb at all? Is there some particular domain logic you would like to place on top of it to constrain it? DynamoDB is already a restful service... Putting your own restful service on top of it may be advantageous, but you would have to convince me of the value of doing so. If you have particular business logic that requires you constraining the functionality, packaging it as a shared library has certain advantages, especially if you can encapsulate that business logic and separate it from the implementation of DynamoDB.
I am assuming that updating the shared library will not be in your control. And clients (library users) will update whenever it suits them.
If the above assumption is true, You should always go with a rest service. Considering few things
Your rest api may use cache instead of calling dynamodb all the time.
You might want to update the schema of the data you want to put in dynamodb.
You may use another db all together.
You may have some validation logic which will certainly evolve over time.
Related
We have different client applications (each is built with a different UI and is targeted to a different sales channels) that are used to capture orders that ultimately need to be processed by our factory.
At first we decided to offer a single "order" microservice that would be used by all these client applications for business rules execution and data storage. This microservice will also trigger our backoffice processes such as client profile update, order analysis, documents storage to our electronic vault, invoicing, communications, etc.
The challenge we are facing is that these client applications are developed by teams that are external to ours (we are a backoffice team only). Each team responsible to develop a client application will be able to offer a different UX to their users (some will allow to save orders in an incomplete state, some wil allow to capture data using a specific worflow, some will use text fields instead of listboxes for some values, etc.).
This diversity of behaviors from client applications is an issue because our microservice logic will become very complex to be able to support all those UI requirements. Moreover, everytime a change will be made to one of the client applications, we will have to modify our microservice which is a case of strong coupling.
My questions are: What would be your best advice to manage this issue? Should we let each application capture the data the way it wants (and persist it if needed in its own database) and let them call our microservice only when an order is complete and compliant to our API contract?
Should we keep our idea of having a single "order" microservice for everyone and force each client application to capture the data the same way?
Any other option?
We want to reduce the duplication of data and business rules in our ecosystem but in the same time we don't want our 'order' microservice to become a mess.
Many thanks for your help.
Moreover, everytime a change will be made to one of the client applications, we will have to modify our microservice which is a case of strong coupling.
This rings alarm bells for me. A change to a UI shouldn't require a change to a backend service. (The exception would be if a new feature were being added to a system and the backend service needed to play a part in supporting that feature, but I wouldn't just call that a change to a client.) As you have said, it's strong coupling, and that's something to be avoided in a microservices environment.
Ideally, your service should provide a generic, programmatic API that is flexible enough to support multiple UIs (or other non-UI applications) without having any knowledge of how the UIs work.
It sounds like you have some decisions to make about what responsibilities your service will and won't take on:
Does it make more sense for your generic orders service to facilitate the storage/retrieval/completion of incomplete orders, or to force its clients to manage this somewhere else?
Does it make more sense for your generic service to provide facilities to assist in the tracking of workflows, or to force the UIs that need that functionality to find it elsewhere?
For clients that want to show list boxes, does it make sense for your generic orders service to provide APIs that aid in populating those boxes?
Should we let each application capture the data the way it wants (and persist it if needed in its own database) and let them call our microservice only when an order is complete and compliant to our API contract?
It really depends on whether you think that's the most sensible way for your service to behave. Something that will play into that will be how similar or dissimilar the needs of each UI is. If 4 out of 5 UIs have the same needs, it could well make sense to support that generically in your service. If every single UI behaves differently to the others, putting that functionality in your generic orders service would amount to storing frontend code somewhere that it doesn't belong.
It seems like there might also be some organisational considerations to these decisions. If the teams using your service are only frontend teams (i.e. without capacity/skills to build backend services), then someone will still have to build the backend functionality they require.
Should we keep our idea of having a single "order" microservice for everyone and force each client application to capture the data the same way?
Yes to the idea of having a single order service with a generic interface for everyone. With regards to forcing client applications to capture data a certain way, your API will only dictate what they need to do to create an order. You can't (and shouldn't) force anything on them about the way they capture the data before calling your service. They can do it however they like. The questions are really around whether your service supports various models of capture or pushes that responsibility back to the frontend.
What would be your best advice to manage this issue?
Collaborate with the teams that will use the service. Gather as much information as you can about the use cases in which they intend to use it. Discover what is common for the majority and choose what of that you will support. Create a semi-formal spec (e.g. well-documented Open API), share it with the client teams, ask for feedback, and iterate. For the parts of the UIs that aren't common across clients, strongly consider telling those teams they'll need to support those elements of their design themselves, especially if they represent significant work on your end.
I have been reading about the articles on the web about the benefits of graphql but so far I have not been able to find a single benefit of it.
One of the most common benefits mentioned in those articles are below?
No Overfetching with GraphQL.
Reducing number of calls made from client side.
Data Load Control Granularity
Evolve your API without versions.
Those above all makes sense but it is not the graphql itself that provides these benefits. Any second layer api written in java/python or any other language would be able to provide this benefits too. It is basically introducing another layer of abstraction above the data retrieval systems, rest or whatever, and decoupling the client side from that layer. After you do that everything you can do with graphql can also be done with any other language too.
Anyone can implement a say scala server that retrieves the data from various api's integrates them, create objects internally and feeds the client with only the relevant part of the data with total control on the data. This api can be easily versioned and released accordingly. Considering the syntax of graphql and how cumbersome it is and difficulty of creating a good cache around it, I can't see why would you use it really.
So the overall question is there any benefits of graphql that is provided to the application because of the graphql itself and not because you implement another layer of abstraction between your applications and your api's?
Best practices known as REST existed earlier, too.
GraphQL is more standarized than REST, safer (no injections) and syntax gives great flexibility in the area of quickly changing client needs.
It's just a good standard of best practices.
I feel GrapgQL is another example of overengineering. I would say "Best standards and practices" are "Keeping It Simple."
Breaking down and object and building a custom one before sending it to the client is very basic.
I understand that both xsodata and xsjs are used for exposing data but why there are two ways? Which one should one use and how the use of xsodata is different from xsjs data.?
Good Question, I will try to give you a little overview. I will describe three SAPUI5 ways of backend implementation.
XSODATA
Let's assume, you have something like a Checklist. You may want to add items to your list, edit or delete them and - obvious - you want to display them. These simple tasks are called CRUD (create, read, update, delete) operations. These Operations are the simplest way of dealing with data. There are no real "hard" queries to get work done and you may operate on very less JOIN's. This can be easyly done with XSODATA. It's a simple REST-Interface.
XSJS
Okay, you have your checklist, but you want to log every single entry, or do analysis or something not-so-easy with it. This is, where XSJS comes into play. With XSJS you have a better control (and much more work needs to be done) of your data. But keep in mind, that you need to code every single step. XSJS is not a real interface, but it's a sapui5 way of handling data, like you would do in any other vanilla-programming-language without a framework.
Node.JS / custom backend
Another, newly (2017) introduced way of handling data at sapui5 is the usage of Node.JS. Node.JS let you write your own RESTful API (node.js is much more powerful than that, but this information must be enough for now). Node.JS is something like the intersection between XSODATA and XSJS: you are able to use a RESTful API (implemented by yourself) with 100% datacontrol. I don't want to go too much into detail, but Node.JS is for advanced applications the state-of-the-art at early '17.
Conclusion
What you might use really depends on your application itself. Personally, I think the best way to start is with XSODATA. If you can't solve certain tasks with only oData, use XSJS for those single cases. In a real-world application with tons of data and complex queries, you might consider Node.JS as your backend-wizard.
useful informations:
OData vs XSJS in SAP Hana Development
https://archive.sap.com/discussions/thread/3688095
http://saphanatutorial.com/sap-hana-xsjs-service/
https://blogs.sap.com/2015/12/08/sap-hana-sps-11-new-developer-features-nodejs/
https://nodejs.org/en/
I am building simple REST deployable using Spring Boot. Decided to create it by using failing acceptance test first followed with TDD until its green.
My module is pretty simple, I have 3 API's:
Retrieving list of data from datastore.
Adds item to datastore.
Deletes item from datastore.
I feel like it is good idea to abstract datastore and have maybe backed by Map data structure for testing purposes and use it with either NoSQL or SQL db if I want to for deployments/releases and end to end testing.
On the service layer side I am unsure since it would just delegate call to repository with no logic.
So standard approach would be controller->service->repository. In my case service does not do much(possible some exception handling but not more) and I will end up with interface and implementation as an extra as well as few more lines of code. I fell like going for controller->repository solution in my situation but it is not a practice I have seen and not sure how others would see it.
What's the best way to implement this sort of system?
I feel like it is good idea to abstract datastore
You are right. The abstraction is called 'Repository' in DDD (Domain Driven Design) for example.
On the service layer side I am unsure since it would just delegate call to repository with no logic.
I'm pretty sure there are data that you want to validate. So you should have a layer in the middle (e.g. the domain layer) which will be in charge of this validation.
Even so, if you feel like your application is simple and doesn't require such layers, go without. You will have less supple design, but more simplicity at first. Be careful: while evolving your app, you could run into trouble.
Hope this will help.
This is rather an opinion based question, but if you are asking whether a 3 layer architecture is a must, to that I say no. Be pragmatic, if you don' see a reason for a class/layer/module to exist, it does not need to exist.
A repository has a purpose (to store/retrieve), and the api layer has a purpose, to offer those things through HTTP.
Here is an article for building small services with the sparkframework: https://dzone.com/articles/building-simple-restful-api
I'm writing an API which uses MongoDB as the storage backend. Let's say the API allows a consumer to query for upcoming events. Let's say some events are private, and for the current user, should not come up in the results.
Should I:
Implement this at the API level. The API code, will be responsible for these checks. The advantage seems to be that if I change storage engines (unlikely), the business code will be intact.
Implement this as a stored javascript function.
At the API level, for the reason you mentioned: you're independent of the underlying storage mechanism of your application.
A good guideline is Persistence Ignorance: make your business logic as little aware of the storage mechanism as possible. This implies that business logic shouldn't be located in your storage layer either. So stored procedures or stored JavaScript functions shouldn't contain business logic. Some advantages of this:
You can swap the underlying database with minimal effort and without having to re-implement your business logic in the new database.
All of your business logic is contained inside your application layer, making the code base easier to understand and debug.
The only functions you should store in MongoDB are 'utility' functions; functions that simplify common operations, such as string operations, but are not tied to your business logic in any way.