Skip to content

Instantly share code, notes, and snippets.

@jhodge-chwy
Last active July 20, 2022 16:49
Show Gist options
  • Save jhodge-chwy/4bb4b43f1d3b6c120d3b283cad2d9fba to your computer and use it in GitHub Desktop.
Save jhodge-chwy/4bb4b43f1d3b6c120d3b283cad2d9fba to your computer and use it in GitHub Desktop.
sub_service_structure.md

Entity Service Refactoring / Restructure

Goal

Decompose/Refactor unwieldy django 'apps' into discrete A-B-C tiers for maintainability, testability, and robustness with future looking potential of extracting the services from the vet-app codebase into their own independent microservices.

Proposed structure

Based on https://chewyinc.atlassian.net/wiki/spaces/~jhodge/pages/486182283/Vet-Platform-App+Code+Guidelines

Request (1) -> A (1) -> B (0+)-> C

A single request should call a single A operation which could call a single B sub-service. This sub-service-b may call multiple Cs to (such as needing both a practice and an user)

Note: A only calling a single B is debatable. If the A is super-thin, then it shouldn't be calling multiple B's unless there is some graphql specific handling to be done that needs multiple

Eg.

StaffCreateForPractice

Request -> staff-a -> staff-b -> [user-c/models, practice-c/models]

API (A)

Contains the GraphQL representations. Nothing in here should be tightly coupled to the Django ORM but instead inherit from graphene.ObjectType.

Business Logic (B)

Handles any calculations / composition that is needed to return results to the C layer. C calls the business layer for operations. Graphql should not be imported within this nor anything having context of graphql. This should only have awareness of requesting from the data layer (C) doing any transforms and returning this to the requestor (C) which then surfaces / formats any errors / responses for graphql.

Data (C)

This is the models.py of Django or any other 'data source' that B needs to request from (ideally within the django app/subservice but B may request from several subservice C layers depending on the needs of the Caller)

C only calls upon Bs which only calls from A C->B->A with responses following the inverse of this.

Example service: Accounts

The current implementation is riddled with long files, partial test coverage and subclassed operations and is tightly coupled to the ORM. The inherited implementation from the original vet-whitelabel-poc fork also has issue which prevent the upgrade of graphene to the next major release (3.x+).

The end result of this will that things no longer inherit from Model* mutations which will remove the decoupling and allow upgrade, as well as refactoring the code for more modularity and maintainability.

Sub-Services

The account service has the following sub-services:

  • Customer
  • Staff
  • Address
  • Tableau & Okta management
  • Password and Pin
  • Preferences

Service Structure

account
├── grapqhl # api would be more accurate, but creates chewypro.api.account.api confusion. graphql is sufficient since everything here will be graphql specific code.
|   ├── queries.py
|   ├── mutations.py (imports from the sub-services eg customer.mutations, account.mutations)
│   └── <subservice - the structure is the same for each>
│       ├── mutations
|       │   ├── operations
|       │   └── resolvers
│       ├── queries
|       │   ├── operations
|       │   └── resolvers
│       └── types
|           ├── entity - consider better name
|           └── fields
├── business - consider better name
│   └── <subservice>
│       ├── mixins - provides the interfaces for the C layer (create/read/update/delete)
|       └── TBD
└── models (data layer)

The above structure would allow for the eventual segmentation into a more isolated subservice - one that may exist outside of the current vet-whitelabel-app codebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment