Blog
/
/
Scale Your React Project: use mocks to decouple Backend from Frontend development
General
General

Scale Your React Project: use mocks to decouple Backend from Frontend development

Aug 16, 2022
Matan Gubkin

Introduction

In many full stack application development teams, it is quite common to have frontend engineers who are frustrated with the developer experience regarding the webapps they are building. This usually happens because the frontend development process in their company is heavily coupled with a backend server and a database behind it. The web app cannot run locally without a dedicated development server.

Many front-end engineers are having a hard time dealing with development server downtime, lack of API, or just need to constantly switch between backend environments. All with the sole purpose of building a feature that lives entirely in their local browser. This can really hurt development velocity, especially in large enterprise organizations which have a lot of potentially breakable moving parts.

There’s a solution here, which can keep your frontend development 100% decoupled from any backend code. This is what this post is about.

What does decoupling the backend from the frontend have to do with developer experience?

Let’s take a look at a traditional feature development process in a full-stack application:

As you can see, throughout the development of an average feature the frontend team is blocked the most. The frontend team is forced to wait for the backend team to finish up their work because without an API, building the frontend part of the feature will be difficult to complete. In most cases the frontend team just waits for the backend team to fully complete their part of the feature.

Doesn’t look too bad? Take a look at a more down to earth early-startup diagram:

About 50% of the development time is spent in “blocked” state. The severity changes between features, teams and companies but the point remains the same. This kind of developer (non-)velocity creates exhaustion, laziness, and extreme lack of productivity. I’ve met FE developers that couldn’t make any progress at all for days because of “external reasons”. This can also create a ping-pong culture that can ultimately end up with people feeling a growing frustration and potentially leaving the company.

The solution: mocks

A proper UI-mocks infrastructure can easily solve this problem. 

If the frontend team creates mocks in the product planning phase, most of those red squares in the frontend team timeline axis can turn to yellow or green (which represent progress and feature complete respectively) because the FE project can live in its own “mock UI bubble”, detached and de-coupled from any external sources.

Here is a developer velocity comparison diagram between a traditional frontend project and a frontend project that relies on mocks for the development process:

No surprises there, obviously. The development of webapps with mocks allows the developer to take full control of all variables. It allows for a development process that is decoupled from any unexpected external source. It also allows starting the development of the feature immediately once the design and specifications in the “product + design phase” are completed.

In my opinion, the most important aspect of developer experience is independence. If I constantly must communicate with other teams in my organization about downtimes, API documents and permissions, it reduces my productivity and my ability to learn new things. Mocks help with all of these things, because all I have to do is to agree on the way a feature should be done, and from that point every team can progress on its own.

{{cta_5}}

Tools and Tips

There are some tools and libraries out there that can help architect mocks pretty easily.

Mock Service Worker Library (MSW)

The most notable open-source package in this space is the Mock Service Worker Library (MSW). Essentially the library intercepts the browser’s network requests, allowing the developer to “force” a custom response for a network request, suited for his needs. 

This library registers a Service Worker that listens to the application's outgoing requests via the fetch event, directs those requests to the client-side library, and sends a mocked response, if any, to the worker to respond with.

Here's a high-level overview of the Mock Service Worker request flow:

The main advantage is that the mocks live as part of the webapp project and not as a separate entity. It could be useful if you’d want to enforce typing, use the mocks for your FE testing infrastructure or easily create data for a customer demo.

JSON Server

Another great mention is the JSON Server library. The library enables the developer to easily create mocks as part of a separated server. It’s a more classic approach to creating mocks but works just as well.

Falso

It is worth mentioning that if you’d want to create data that looks real, you might want tools that can help you generate random data. A great library for that purpose is Falso. The library offers a variety of data utilities to create random data and it has great documentation.

Make sure the mocks align with the real API

It would be a pity if you’ll work hard to develop a particular feature, only to find out that the mocks you’ve created don’t align with the real API of the feature. The mocks don't have to be 100% accurate, because that would slow down development. But they should provide a pretty good initial representation of how the API will actually behave

Don’t over-engineer mocks

If you find yourself complicating things, reconsider your actions. The mocks are not a feature you are required to build. It is merely a tool that helps you build features faster. Adopt the “good enough for this feature” approach, and scale it up as your team grows.

Make sure other FE engineers are aware of the ability to build mocks on their own

Using mocks in a FE project is a relatively new approach. Most FE engineers out there are not familiar with the concept. Make sure everyone knows about the ability to mock things and teach them how to create mocks on their own.

Don’t mock mutation routes

What I mean by that is that your backend server probably has routes that ultimately update the records in the database. 

I highly recommend to make it simple and mock only the status codes and not manage a state just to update/create/delete records or data in the server. 

This is because generally speaking, you need the mocks to display data in the webapp. Handling updates, creation or deletions would require you to have some kind of client-side state just for this purpose, which complicates the concept a lot. I rarely mock anything other than GET requests. Our purpose is not to create a second backend server in our project, but to create the minimal shallow version of our API to the point where it will be “good enough”.

{{ebook}}

Conclusion

Using mocks as part of your development process can have a tremendous impact on your developer experience and velocity. It is also a relief to the other teams in the organization because they do not have to rush with their part of the features just in order to not leave the frontend engineers in a blocked state or creating numerous dev environments.

{{cta}}

Book a demo right now to check out Port's developer portal yourself

Book a demo
{{jenkins}}

It's a Trap - Jenkins as Self service UI

Read more
{{gitops}}

How do GitOps affect developer experience?

Read more
{{ebook}}

It's a Trap - Jenkins as Self service UI. Click her to download the eBook

Download eBook
{{cyberark}}

Learning from CyberArk - building an internal developer platform in-house

Read more
{{dropdown}}

Example JSON block

{
  "foo": "bar"
}

Order Domain

{
  "properties": {},
  "relations": {},
  "title": "Orders",
  "identifier": "Orders"
}

Cart System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Cart",
  "title": "Cart"
}

Products System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Products",
  "title": "Products"
}

Cart Resource

{
  "properties": {
    "type": "postgress"
  },
  "relations": {},
  "icon": "GPU",
  "title": "Cart SQL database",
  "identifier": "cart-sql-sb"
}

Cart API

{
 "identifier": "CartAPI",
 "title": "Cart API",
 "blueprint": "API",
 "properties": {
   "type": "Open API"
 },
 "relations": {
   "provider": "CartService"
 },
 "icon": "Link"
}

Core Kafka Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Kafka Library",
  "identifier": "CoreKafkaLibrary"
}

Core Payment Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Payment Library",
  "identifier": "CorePaymentLibrary"
}

Cart Service JSON

{
 "identifier": "CartService",
 "title": "Cart Service",
 "blueprint": "Component",
 "properties": {
   "type": "service"
 },
 "relations": {
   "system": "Cart",
   "resources": [
     "cart-sql-sb"
   ],
   "consumesApi": [],
   "components": [
     "CorePaymentLibrary",
     "CoreKafkaLibrary"
   ]
 },
 "icon": "Cloud"
}

Products Service JSON

{
  "identifier": "ProductsService",
  "title": "Products Service",
  "blueprint": "Component",
  "properties": {
    "type": "service"
  },
  "relations": {
    "system": "Products",
    "consumesApi": [
      "CartAPI"
    ],
    "components": []
  }
}

Component Blueprint

{
 "identifier": "Component",
 "title": "Component",
 "icon": "Cloud",
 "schema": {
   "properties": {
     "type": {
       "enum": [
         "service",
         "library"
       ],
       "icon": "Docs",
       "type": "string",
       "enumColors": {
         "service": "blue",
         "library": "green"
       }
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "system": {
     "target": "System",
     "required": false,
     "many": false
   },
   "resources": {
     "target": "Resource",
     "required": false,
     "many": true
   },
   "consumesApi": {
     "target": "API",
     "required": false,
     "many": true
   },
   "components": {
     "target": "Component",
     "required": false,
     "many": true
   },
   "providesApi": {
     "target": "API",
     "required": false,
     "many": false
   }
 }
}

Resource Blueprint

{
 “identifier”: “Resource”,
 “title”: “Resource”,
 “icon”: “DevopsTool”,
 “schema”: {
   “properties”: {
     “type”: {
       “enum”: [
         “postgress”,
         “kafka-topic”,
         “rabbit-queue”,
         “s3-bucket”
       ],
       “icon”: “Docs”,
       “type”: “string”
     }
   },
   “required”: []
 },
 “mirrorProperties”: {},
 “formulaProperties”: {},
 “calculationProperties”: {},
 “relations”: {}
}

API Blueprint

{
 "identifier": "API",
 "title": "API",
 "icon": "Link",
 "schema": {
   "properties": {
     "type": {
       "type": "string",
       "enum": [
         "Open API",
         "grpc"
       ]
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "provider": {
     "target": "Component",
     "required": true,
     "many": false
   }
 }
}

Domain Blueprint

{
 "identifier": "Domain",
 "title": "Domain",
 "icon": "Server",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {}
}

System Blueprint

{
 "identifier": "System",
 "title": "System",
 "icon": "DevopsTool",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "domain": {
     "target": "Domain",
     "required": true,
     "many": false
   }
 }
}
{{tabel-1}}

Microservices SDLC

  • Scaffold a new microservice

  • Deploy (canary or blue-green)

  • Feature flagging

  • Revert

  • Lock deployments

  • Add Secret

  • Force merge pull request (skip tests on crises)

  • Add environment variable to service

  • Add IaC to the service

  • Upgrade package version

Development environments

  • Spin up a developer environment for 5 days

  • ETL mock data to environment

  • Invite developer to the environment

  • Extend TTL by 3 days

Cloud resources

  • Provision a cloud resource

  • Modify a cloud resource

  • Get permissions to access cloud resource

SRE actions

  • Update pod count

  • Update auto-scaling group

  • Execute incident response runbook automation

Data Engineering

  • Add / Remove / Update Column to table

  • Run Airflow DAG

  • Duplicate table

Backoffice

  • Change customer configuration

  • Update customer software version

  • Upgrade - Downgrade plan tier

  • Create - Delete customer

Machine learning actions

  • Train model

  • Pre-process dataset

  • Deploy

  • A/B testing traffic route

  • Revert

  • Spin up remote Jupyter notebook

{{tabel-2}}

Engineering tools

  • Observability

  • Tasks management

  • CI/CD

  • On-Call management

  • Troubleshooting tools

  • DevSecOps

  • Runbooks

Infrastructure

  • Cloud Resources

  • K8S

  • Containers & Serverless

  • IaC

  • Databases

  • Environments

  • Regions

Software and more

  • Microservices

  • Docker Images

  • Docs

  • APIs

  • 3rd parties

  • Runbooks

  • Cron jobs

Check out Port's pre-populated demo and see what it's all about.

Check live demo

No email required

Contact sales for a technical product walkthrough

Let’s start

Open a free Port account. No credit card required

Let’s start

Watch Port live coding videos - setting up an internal developer portal & platform

Let’s start

Check out Port's pre-populated demo and see what it's all about.

(no email required)

Let’s start

Contact sales for a technical product walkthrough

Let’s start

Open a free Port account. No credit card required

Let’s start

Watch Port live coding videos - setting up an internal developer portal & platform

Let’s start

Let us walk you through the platform and catalog the assets of your choice.

I’m ready, let’s start