1

I did some googling, and I was directed to Software Engineering to ask architecture questions. If you know of a different forum that could help me, please direct me to it

I recently started learning about microservices, and would like to build an experimental app (the backend) just for practice. I’ll explain the app requirements, and after that outline my microservices-based solutions (and some doubts/questions I have). I’d love to get your feedback, or your approach to building this app using microservices.

Please note: I am a beginner when it comes to microservices, and still learning. My solution might not be good, so I’d like to learn from you.

The App (Silly App):

The purpose of this app is to make sure users eat carrots four times a week. App admins create a carrot eating competition that starts on day x and ends 8 weeks after day x. Users can choose whether or not to participate in the competition. When a user joins the competition, they need to post a picture of themselves eating a carrot. The admin approves/rejects the picture. If approved, the carrot eating session counts towards the weekly goal, otherwise it does not. At the end of each week, participating users are billed $10 for each carrot eating session they missed (for example, if they only eat carrots two times that week, they’re billed $20). That $20 goes into a “money bucket”. At the end of two months, users who successfully ate carrots four times a week every single week divide the money in the bucket among themselves. For example, assume we have users A, B, C. User A missed all carrot eating sessions for two months (puts $40 a week in the money bucket, so $320 by the end of two months). Users B and C eat their carrots four times a week consistently for two months. So users B and C take home $320/2 = $160.

Simplification: I wanted to start simple. Forget about money. Forget about admin approval. We can add that later. For now, let’s focus on a very simplified version of the app.

  • User can signup/login/logout to app
  • When a user signs up, they are automatically enrolled into the next carrot eating competition
  • Users can post an image of him/herself eating a carrot
  • Users can see a feed of other users images (similar to instagram, except all pics are of people eating carrots)
  • Users can access their profile - a page that displays how they’re doing in the competition: I.e,for each week, how many carrots they ate. And which weeks they failed at.
  • At any point in time, users can access a page that shows who the current winners are (i.e, users who did not miss a carrot eating session yet).

Is this an appropriate simplification to start with?

Thinking Microservices - Asynchronous Approach:

Auth Service: Responsible for Authenticating User

Database:

  • User Table: id, username, email, password

Routes:

  • POST /users/new : signup
  • POST /users/login: login
  • POST /users/signout: signout

Events:

  • Publishes
    • User: created

Image Service: Responsible for Saving Images (upload to Amazon S3)

Database:

  • User Table: userId, username
  • Image Table: imageId, userId, dateUploaded, imageUrl

Routes:

  • POST /users/:userId/images: Post new image
  • GET /users/:userId/image/:imageId: Return a specific image
  • GET /images: Return all images (Feed)

Events:

  • Publishes:
    • Image:created (userId, imageId, imageUrl, dateUploaded)

Competition Service: Responsible for managing competition

Database:

  • Competition table: id, startDate, duration
  • User table: id, username, competitionId, results (see below)

Routes:

  • POST /competition: create a competition
  • GET /competition/:competitionId/users/:userId: get results for a specific user
  • GET /competition/:competitionId/users: get a list of users participating in competition (see below)
  • GET /competition/:competitionId: get a list of winners, and for each looser how many workouts they missed

Events:

  • Listens:
    • User:created
    • Image:created

In the database, user table, Results is the JSON equivalent of

results = {
   week1: {
       date: 'oct 20 2020 - oct 27 2020',
       results: ['mon oct 20 2020', 'tue oct 21 2020', 'thur oct 23 2020'],
   },
   week2: {
       date: 'oct 28 2020 - nov4 2020',
       results: ['somedate', 'somedate', 'somedate', 'somedate'],
   },
   week3: {
       date: 'nov 5 2020 - nov 12 2020',
       results: [],
   },
   ...
}

Better ideas on how to store this data appreciated

GET /competition/:competitionId returns

const results: {
 winners: [{ userId: 'jkjl'; username: 'jkljkl' }, { userId: 'jkjl'; username: 'jkljkl' }];
 loosers: [
   { userId: 'kffjl'; username: 'klj'; carrotDaysMissed: 3 },
   { userId: 'kl'; username: 'kdddfj'; carrotDaysMissed: 2 }
 ];
};

What do you think of this? How would you improve it? Or would you approach this from an entirely different way?

1

I recommend that you first design your API (i.e., identifying services and methods, and their consumers) and avoid talking about data storage. With that, walk through your user stories and make sure that the API accounts for everything.

The most important consideration is going to be what parts of the API will be exposed externally, since modifying those in the future might require involving other businesses or end users; possibly paying customers. Those parts of the API should be as future-proof as possible. Internal-only parts of the API are quite a bit easier to change.

As a first implementation, you can just return canned responses from most of the service methods, e.g., a map from requests to responses. This will be useful for unit-testing, anyway.


As far as your design, I think you need more user-facing services that then deal with internal services to handle data retrieval and updates:

  • A service for signing up. (Separate because it requires data updates in multiple places.)
  • A service for signing in. (Might need to provide an authn token for other API calls.)
  • A service for maintaining one's own account.
  • A service for admin actions.
  • A service for user actions other than account maintenance.
  • A service for viewing things. (Separate because it will likely be read-only.)

The point of this is to separate what the user can do from how it's actually done. You don't want your mobile app making a bunch of calls to the API to perform a single action for the user; it's better to have one call for one user action.

This way you're free to change how things happen internally, which is critical for being able to scale the entire application.

For example:

  • You might find that requests for data to display are orders of magnitude more frequent than requests to upload a photo. Putting the two in separate services allows you to replicate them independently to account for amount of traffic.
  • You will likely want to limit write access to the databases as much as possible. Keeping reads in a separate service allows you to limit write access to services that only perform updates. (You would still want an internal service to manage the database, rather than having direct access by multiple services.)
  • Sign-up and sign-in services might be more prone to security weaknesses, and therefore might need to be updated more often and more quickly. Keeping them separate prevents unrelated features from slowing down or blocking updates.
| improve this answer | |
  • Maybe add an example on how scalability could affect on the API design decisions – lennon310 Nov 21 at 4:09
  • @lennon310 Added a few. Thanks for the suggestion! – Kevin P. Barry Nov 21 at 19:02
  • Good stuff on keeping things separate, +1 – lennon310 Nov 22 at 1:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.