Skip to content

Latest commit

 

History

History
116 lines (77 loc) · 8.87 KB

map_to_the_app.md

File metadata and controls

116 lines (77 loc) · 8.87 KB

🗺️

As we have built our app in React Native, our understanding of how to build software has evolved. As our understanding grows, newer code uses newer techniques. Older code is often left un-updated. It can be difficult to orient oneself around what the current preferred practices are.

This document is a map. Not of Eigen at a specific time, but a map of how we got here and where we want to go next. This is a living document, expected to be updated regularly, of links to:

  • Example code.
  • Pull requests with interesting discussions.
  • Conversations on Slack.
  • Blog posts.

Links should point to specific commits, and not a branch (in case the branch or file is deleted, these links should always work). But it's possible that a file is outdated, that our understanding has moved on since it was linked to; in that case, please update this document.

Current Preferred Practices

The app is written in Objective-C and Swift, with React Native added in 2016. We only ship an iOS app, and do not yet use React Native for an Android app.

Objective-C and Swift (sometimes called "Native" code) are responsible for the following parts of the app:

  • Sign up/in flow ("onboarding").
  • Live Auctions Integration (LAI) view controller and networking.
  • The Auction view controller.
  • The SwitchBoard (see "SwitchBoard" section below) to navigate between view controllers.
  • The top-level tab bar, and each tab's navigation controller.
  • Deep-link and notification handling (via SwitchBoard).
  • Analytics for Native UI.
  • Initializing the React Native runtime.

Everything else is written in React Native.

Use React Native for new feature development

New features should be built in React Native. The React Native runtime currently requires an existing user ID and access token to be loaded, and sign up/in is still handled in Native code.

We used to have many different renderX functions throughout our components, but today we prefer to have a single render() function in a component. See this PR for our rationale and a comparison of approaches.

Leverage TypeScript to prevent runtime bugs

We use TypeScript to maximize runtime code safety. In April 2020, we adopted TypeScript's strict mode. This disables "implicit any" and require strict null checks. The change left a lot of comments like this throughout the codebase:

// @ts-ignore STRICTNESS_MIGRATION

Our goal is to reduce the number of STRICTNESS_MIGRATION migrations checks to zero over time. We use CI tooling to require PRs never to increase the number. You can opt in to helping out by requiring all the files you change to fix all the migration comments by running the following command:

touch .i-am-helping-out-with-the-strictness-migration

Keep File Structure Organized (in progress)

Everything in src/ is React Native. Within this folder, things can be a bit of a mess. We are working on cleaning it up. Check back here for more later.

TODO: Figure out what we want our directory structure to be and define it here.

Use Relay for Network Requests

Data should be loaded from Metaphysics, Artsy's GraphQL server. Requests to Metaphysics should be made through Relay.

styled-system / styled-components

Write unit tests for new components

Unit testing on Emission is a bit all over the place. Some top-level notes:

  • We prefer react-test-render over enzyme, and would ultimately like to remove enzyme.
  • We prefer relay-test-utils over our existing MockRelayRenderer.
  • We have native unit tests too. See getting_started.md
  • We don't like snapshot tests; they produce too much churn for too little value. It's okay to test that a component doesn't throw when rendered, but use extractText (or similar) to test the actual component tree.

Here are some great examples of what tests and test coverage should look like.

Use the Native Switchboard for Navigation (for now...)

Our React Native code ("Emission") is used by our Native code ("Eigen"). They used to be two repositories but were combined in February 2020. Traces of the separation remain. The structure we originally took is described in this blog post. Interop between JavaScript and Native can be tricky.

Most interactions are made through a "SwitchBoard" to open links. Other interactions are handled by the APIModules, for example when Eigen needs to invoke some kind of callback.

Analytics

There is extensive inline documentation in our tracking code, including examples.

Miscellaneous