Trading Application with embedded Order Book with responsive design.
Check it out: https://trading-platform.vercel.app/
- Version with debug logs: https://trading-platform.vercel.app/?debug
- Version with fps metrics: https://trading-platform.vercel.app/?fps
- Version with fps metrics and animation to force frame redraws: https://trading-platform.vercel.app/?fpsAni
yarn startStart dev server with hot reloading
yarn sanityRun all important checks to validate your changes (test/lint/e2e/build)
yarn buildBuild production version
yarn start:prodStart production server
E2E and Integration tests:
yarn e2eBuilds default project and runs headless cypress e2e tests
yarn testRuns all unit tests from projects and libraries.
Apps – Applications which consume libraries to produce ‘end’ product like Trading App variant with embedded modules.
Can import and embed modules. Either by static or dynamic imports (module federation). Apps can only implicitly include other apps (cypress e2e is one example). Apps cannot be imported by other parts. Apps can import all other parts. Apps also include e2e testing which is core testing flow used in this app.
Modules – Modules are encapsulated functionality which can be embedded in the apps (implicitly or explicitly). In the future we could support webpack federation and each module would be build separately.
Model – Data modeling. Can be imported by other models or modules.
Data – Data service layer. Responsible for data retrieval/sending for various communication methods. One example is Streaming data layer using WebSocket.
Utils – Small reusable chunk of code not falling into other concepts. Small utility/helper functions. Should not import from any other libs. Can be used by all of them.
UI – Contains library of ui components. Follows Atomic Design pattern.
Eslint rules ensure that invalid imports are not possible.
.eslintrc.json to learn more about constraints.
E2E and Integration tests
Majority of testing is done in cypress with mocked WebSocked server for various scenarios.
This allows for extensive coverage combined with ease of creating tests with available live preview.
Tests are included as part of separate app called app/trading-platform-e2e which implicitly depends on trading-platform app.
Specific functions are covered using unit tests written in jest and using testing-library as support.
Styled components are tested using snapshotting. Not ideal in all scenarios, but for styled components works great as we need to
focus on generated css definitions, which are small and easy to compare.
For CPU/Memory usage, used built it devtools monitoring tool. No issues found for prolonged app usage.
Scale of repaints was taken into consideration. Using width change on row caused smaller repaint areas then transform/gradient/background-size solutions.
Amount of layouts changes in all solutions was similar.
Performance testing was done on various devices listed below.
To get stable FPS values, I’ve built FPS tool which also forces each frame to be redrawn.
Without it, browsers can allocate frames as they “please” end do not try to run at constant 60fps.
In addition to performance tests using FPS monitoring, I’ve also validated cpu measurement for reducers and react ‘jobs’ using Performance DevTools.
Main cost post reducing and react handling is layout and painting.
Ways of trying to limit layout cost using css gradients, css background size fills or transforms, didn’t produce any value and increased repaints to whole grid.
Another analysis done was checking impact of key for rows being defined as index vs price. Price as key, produced worse results for order book scenario due to amount of changes in a grid and simple rows it’s more performant to actually use index.
Also, tried to limit amount of re-layouts caused by simple text update. Added overflow: hidden where possible to at least simplify
Browser layout calculations. To fully get rid of it, I would need to change strategy to calculate each position manually, and it seems
like doing that seems like an overkill. However, if grid was intended to scale to thousands of items, different strategy would be used then
current one (virtualization, canvas, manual position calculation and transforms).
Alternative option could also be rendering size bars using canvas. But this seems like overkill for a problem, so didn’t pursue it.
If I had more time, I would play with idea of trying out different performance strategies based on rows count. There might a point
where some approach have advantage over another.
Another idea for later would be splitting up rendering steps into two. However, not sure how to do it
without affecting business requirements/sorting, etc. But it would help on low-end devices sometime struggling to handle
bigger updates redrawing effectively every row/cell.
- NX – project monorepo setup bootstrapping
- Yarn – node modules package management
- React – Frontend rendering library
- Typescript – Building and strong typing
- Styled Components – CSS in JS
- Redux – State management
- Redux-Toolkit – Helper functionalities for State Management
- Redux-Toolkit Query – Redux ‘framework’ for defining standardized redux/store handling for data fetching and streaming.
- WebSocket – Data streaming
- Jest – Unit tests
- Cypress – E2E and Integration tests
Moto G7 Play | Low End | 2019
Pixel 2 | 2017
Redmi Note 8 | 2019
Samsung s8 | 2017
Samsung s9 | 2018
You can run below command to see dependency graph for the whole project
yarn nx dep-graph --watch=true
Then visit: http://127.0.0.1:4211
Available scripts commands
start– Start development watch server
start:production– Start production server. Use to test production builds
sanity– Runs all validation checks (unit/e2e/builds/lint)
build– Build production version of default app which is currently trading-platform app
lint– Run lint on all projects and libraries
test– Run all unit/jest tests from all projects and libraries
test:coverage– Build unit/jest coverage for all projects and libraries
e2e– Build production version of default app and run e2e tests headless-ly for it
e2e:watch– Start development server with watch and run e2e in window mode
e2e:coverage– Generate coverage for e2e tests on production version of default app
coverage– Build and merge coverage for all projects and libraries. Currently, e2e is not merged due build setup differences between app and libs
You can also use all available nx commands for managing and working with monorepo workspace.