Microservice Tech Stack at Rungway -Part 2

Claudio Consolmagno
Rungway
Published in
6 min readFeb 18, 2020

This is part 2 of a 3 part blog post series related to the development of microservices at Rungway. In the first part we wrote an overview of the different technology choices in our microservice infrastructure. In this second post we will write about choices in creating new services vs changing existing ones. The third and final post will be regarding our testing methodology.

Photo by Robert Anasch on Unsplash

Change Existing Service or Add New Service

Often when a new feature needs to be developed we need to decide whether to integrate it as part of an existing service or create a brand new service. If there’s a clear line separating a new feature from other services it makes sense to simply create a new one. A lot of times though there is a blurred line and that decision involves some debate between the backend engineers, posing questions such as “how much extra complexity this will add to the existing service?”, “how much coupling is there between the new feature and the existing service in terms of behaviour or data model?”. The biggest consideration probably comes down to that last point, data model. “Does it make sense for this new feature to be integrated within an existing data model or can it be separate?”.

We picked here 2 cases where we had a new feature to be developed related to user content and we debated whether or not to include it in our “discussion-service” service. In both scenarios there were good arguments for both sides and here we try to explain our reasoning in picking one over the other. After we talk about both scenarios, we’ll give a few more thoughts regarding this subject.

Scenario A: New Service

When dealing with user generated content a feature that is present in most products is the “reporting” of user content. Users are allowed to report content that they think break Terms & Conditions and that report needs to be reviewed internally. In the Rungway platform we have that feature.

To give a quick background, we currently have a “discussion-service” which is where content related functionality lives. Creating new discussions, responses to discussions, comments, reactions, etc, most things to do with user generated content goes through here. On paper, it sounds as if this is the correct place for reporting to live, close to the content they refer to.

However, what functionality do you actually need from discussion-service in order to create a report? Not much, you just need to know if the user can access the content they are reporting (i.e. you can’t report content you don’t have access to) and also an internal state needs to be flipped on the content to signify it’s been reported. There’s no logic from discussion-service that it makes use of and it doesn’t necessarily need direct access to the data model. Reporting is related to content but it doesn’t need to be part of the content.

In a new “reporting-service” we can simply call an endpoint on discussion-service to check user access and another endpoint to flip the content state. That is a simple one-way interservice communication. Other things related to reporting don’t need anything from discussion-service, e.g. Maintaining the reporting store or sending events to our event processing pipeline.

In the end can this be its own service? Yes! With a bit of overhead of course (in the interservice communication). Do the benefits of having a new service outweigh this overhead? We think so. The new “reporting-service” can have its own data model isolated from discussions as well as hiding any logic and apis specific to reporting, making it much easier to manage and test compared to if it was part of the discussion-service. At any point if new features (or bugs!) come up related to reporting we know exactly where to look.

Scenario B: Integrating Into An Existing Service

As mentioned in the Scenario A section above, the discussion-service is where most content related functionality lives. It also includes “reactions”. In a discussion, users can anonymously “react” with 4 different types of reactions: “Great Idea”, “Agree”, “I support you” and “Important”. For responses and comments you can also react but with only one reaction type: “Like”.

When we initially came to implement reactions we talked about whether this should be a separate service (e.g. a “reactions-service”) or be part of discussion-service. Similar to reporting, reactions would have their own data store and api endpoints and they don’t necessarily need anything from discussion-service other than checking user access and referencing discussions. However, differently to reporting, the content resource models (discussion, response and comment) would ideally contain reactions. For example when you call the endpoint on discussion-service to get discussions, the returned discussions would ideally contain the (aggregated) reactions count. This makes sense, 99% of the time you are getting a discussion you also want the reactions. We’d need to have a strong reason to split that into multiple calls to discussion-service and a possible reactions-service.

Let’s say we were ok with splitting it into multiple calls. In that case, we’d also need to solve paging api calls. We have paged content apis so the front-end calls a single endpoint to get the “first page” of discussions, and each discussion needs to contain aggregated reactions ready to be displayed. So let’s say we had 10 discussions on that page, do we want to have the front-end calling discussions-service once and then reactions-service 10 times to get their reactions? Even if we create bulk apis, we’d need a minimum of 2 api calls every time you need to access content from the front-end.

A possible solution to that issue would be for discussion-service itself to call reaction-service so that it is transparent to the front-end. But now we introduce a two-way dependency where reaction-service depends on discussion-service and vice-versa. This is arguably the worst case scenario, adding two-way (or circular) dependencies over time tend to become more and more complex and could cause very unexpected and troublesome issues. That is probably a sign that they should actually be together and not separated, or, a significant design change needs to be made.

So here we are: create a new service that would add complexity to front-end and other apis that need to get content from discussion-service, or, integrate it with discussion-service which would make the service more complex but consumers to this service aren’t much impacted. We went with the latter option.

Photo by Startaê Team on Unsplash

Other thoughts

Looking back at Scenario A, and our decision at the time it does seem like creating a new service makes much more sense than integrating it and was the correct decision. For Scenario B however, it’s much more blurred. But our decision to integrate reactions within discussion-service doesn’t have to be final. We could always come back to it at some point and work out a different way to extract reactions into its own service, probably when new features or substantial changes need to be made to it. Rungway is a living and breathing product with changes frequently happening so it’s likely things will get changed there at some point.

To Be Continued…

This concludes part 2 of this series. In part 3 (the final part) we’ll talk about our testing methodology that goes into our services at different levels of abstraction.

--

--

Claudio Consolmagno
Rungway
Writer for

Software Developer at Rungway. Building tools to help employees share work advice with the power of anonymity.