Skip to content
This repository has been archived by the owner on Apr 21, 2021. It is now read-only.

KengoTODA/test-backend

 
 

Repository files navigation

Wiredcraft Back-end Developer Test

Coverage Status

Policy to design the service

Framework and library

Architecture

Apply the four-tier architecture for better maintainability. Nowadays maintainability is most important software product quality for team development, to keep the product growing and changing.

See ARCHTECTURE.md for detail.

How to debug this app

To develop and test the product, you need a MongoDB instance listening the 27017 port in local. You can run it in container, to keep your local env clean:

docker pull mongo:4.4
docker run -it -p 27017:27017 mongo:4.4

To test with production build, use docker-compose then it will launch necessary service and config for production:

docker-compose build
docker-compose up

Guideline for feature development

As a backend engineer, consider three kinds of characteristic:

  1. How we design a RESTful interface?
  2. How we design domain model?
    • In domain tier: Represent domain's properties and behaviours.
    • In application tier: Represent use cases and exceptions.
  3. How we persist data in database?

Case 1: Friends feature

When we have a new requirement like "followers/following" or "friends" feature, consider following requirements:

When code, The 'follow' is User's behaviour, so implement a follow(User) method in User class like:

private readonly friends: Set<UserId>;
private readonly followers: Set<UserId>;

follow(another: User) {
    this.follower.add(another.userId);
    another.friends.add(this.userId);
}

Then get user's input (DTO) in a controller, and provide it to a method in application service which calls follow(User) like:

async follow(from: UserId, to: UserId): Promise<void> {
    const [fromUser, toUser] = await Promise.all(
        this.repo.find(from),
        this.repo.find(to)
    );

    fromUser.follow(toUser);

    // TODO: keep consistency
    return Promise.all(
        repo.update(fromPromise),
        repo.update(toPromise)
    );
}

Case 2: Geospatial search feature

MongoDB provides geospatial query support including nearSphere operator, so design the repository API to use this. We also need to consider several points:

  • Frequency of search query
    • If we need scalability, we can consider to apply the CQRS pattern and use isolated datastore.
  • How to sort friends
    • Deoends on business requirements, we may sort result by distance, UserId or another property.
  • Need paging feature or not
    • It could be needless if we need just a few friends (e.g. for recomendation).

The geospatial search is not behaviour a use case, so we add a method to application service. It receives a UserId, distance and limit to search:

async searchNearbyFriends(id: UserId, distance = DEFAULT_DISTANCE, limit = DEFAULT_LIMIT): Promise<User[]> {
    if (distance <= 0) {
        distance = DEFAULT_DISTANCE;
    }
    distance = Math.min(limit, MAX_DISTANCE);

    if (limit <= 0) {
        limit = DEFAULT_LIMIT;
    }
    limit = Math.min(limit, MAX_LIMIT);

    const user = await this.repo.find(id);
    return repo.searchNearbyFriends(user, distance, limit);
}

We can encapsule the logic complexity into datastore in this scenario. It makes code simple but we need to evaluate datastore performance and maintainability carefully.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 97.3%
  • JavaScript 1.5%
  • Other 1.2%