gitpoint / git-point

GitHub in your pocket :iphone:
https://gitpoint.co/
MIT License
4.72k stars 789 forks source link

Redux refactoring steps #761

Open machour opened 6 years ago

machour commented 6 years ago

Sharing here what I have in mind for the big Redux refactoring.

Step 1 : Pagination

Migrate all the lists fetched from the API to use pagination This is the currently ongoing step and is tracked in #751

Step 2 : Single entity retrieval

Migrate all the single entities retrieval to the new API. This have been done for organizations in #752 for example, and will be tracked once #751 is closed.

Step 3 : Counts

Migrate counting operations to the new API.

For example: Getting the number of notifications.

Step 4 : PUT / PATCH / DELETE

Migrate these operations on single entities to the new API. Example: Create/Update/Delete comment

Step 5 : Source tree cleaning

When step 5 is closed, all our directories will be looking like below since we will have removed all .actions.js .reducer.js *.types.js files:

src/organization/
├── index.js
└── screens
    ├── index.js
    └── organization-profile.screen.js

A PR will be made to get rid of the screens folder:

src/organization/
├── index.js
└── organization-profile.screen.js

Step 6 : Nested schemas in Normalizr & attributes clean up

For now, every Normalizr schema is independent. So a "repository" looks like:

{
  "id": 86202845,
  "name": "git-point",
  "full_name": "gitpoint/git-point",
  "owner": {
    "login": "gitpoint",
    "id": 30082377,
    "avatar_url": "https://avatars0.githubusercontent.com/u/30082377?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/gitpoint",
    "html_url": "https://github.com/gitpoint",
    "followers_url": "https://api.github.com/users/gitpoint/followers",
    "following_url": "https://api.github.com/users/gitpoint/following{/other_user}",
    "gists_url": "https://api.github.com/users/gitpoint/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/gitpoint/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/gitpoint/subscriptions",
    "organizations_url": "https://api.github.com/users/gitpoint/orgs",
    "repos_url": "https://api.github.com/users/gitpoint/repos",
    "events_url": "https://api.github.com/users/gitpoint/events{/privacy}",
    "received_events_url": "https://api.github.com/users/gitpoint/received_events",
    "type": "Organization",
    "site_admin": false
  },
  "private": false,
  "html_url": "https://github.com/gitpoint/git-point",
  "description": "GitHub in your pocket :iphone:",
  "fork": false,
  "url": "https://api.github.com/repos/gitpoint/git-point",
  "forks_url": "https://api.github.com/repos/gitpoint/git-point/forks",
  "keys_url": "https://api.github.com/repos/gitpoint/git-point/keys{/key_id}",
  "collaborators_url": "https://api.github.com/repos/gitpoint/git-point/collaborators{/collaborator}",
  "teams_url": "https://api.github.com/repos/gitpoint/git-point/teams",
  "hooks_url": "https://api.github.com/repos/gitpoint/git-point/hooks",
  "issue_events_url": "https://api.github.com/repos/gitpoint/git-point/issues/events{/number}",
  "events_url": "https://api.github.com/repos/gitpoint/git-point/events",
  "assignees_url": "https://api.github.com/repos/gitpoint/git-point/assignees{/user}",
  "branches_url": "https://api.github.com/repos/gitpoint/git-point/branches{/branch}",
  "tags_url": "https://api.github.com/repos/gitpoint/git-point/tags",
  "blobs_url": "https://api.github.com/repos/gitpoint/git-point/git/blobs{/sha}",
  "git_tags_url": "https://api.github.com/repos/gitpoint/git-point/git/tags{/sha}",
  "git_refs_url": "https://api.github.com/repos/gitpoint/git-point/git/refs{/sha}",
  "trees_url": "https://api.github.com/repos/gitpoint/git-point/git/trees{/sha}",
  "statuses_url": "https://api.github.com/repos/gitpoint/git-point/statuses/{sha}",
  "languages_url": "https://api.github.com/repos/gitpoint/git-point/languages",
  "stargazers_url": "https://api.github.com/repos/gitpoint/git-point/stargazers",
  "contributors_url": "https://api.github.com/repos/gitpoint/git-point/contributors",
  "subscribers_url": "https://api.github.com/repos/gitpoint/git-point/subscribers",
  "subscription_url": "https://api.github.com/repos/gitpoint/git-point/subscription",
  "commits_url": "https://api.github.com/repos/gitpoint/git-point/commits{/sha}",

a lot of this data (assignees_url, tags_url, ..) is irrelevant to us, and simply clutters the store. a PR will be made to cherry pick what goes in the store by working on our schemas.

Additionnaly, we will start using nested Schemas, so that the "owner" point to the relevant Object for the store, instead of containing all its attribute:

{
  "id": 86202845,
  "name": "git-point",
  "full_name": "gitpoint/git-point",
  "owner": "gitpoint", // <---- This is the "id" of the organization in our store
  "private": false,
  "html_url": "https://github.com/gitpoint/git-point",
  "description": "GitHub in your pocket :iphone:",
 ....

Once done, our store will have a minimal footprint, and visiting the Events screen for example will pre-populate data for next screens. (performance ⚡️)

Step 7 : GraphQL

With the store completely restructured, and schemas cherry picking kept attributes, adding GraphQL support should be really painless.

We'll just have to make it so that entities/attributes retrieved from GraphQL match our current structure, and things should work seamlessly. If needed, a second Proxy will be created along with new Schemas to adapt GraphQL attributes names.

We'll adapt our REST entities to match the GraphQL naming.

Step 8 (or 6.5): Deep Linking

The idea here is to make sure that every screen of our application can be accessed directly, with an empty redux store.

More information about this: https://github.com/gitpoint/git-point/pull/752#discussion_r177601220

Once we're there, GitPoint should be able to intercept & handle any github.com URL, and we will have a nice deep linking feature. (#376)

Step 9: Why only github?

Now that we reached the mountain top, we will be able to consider making GitPoint compatible with GitLab / BitBucket:

  1. Split RestClient into a base Client and a GitHubClient
  2. Implement methods for the other providers with the same namespacing/prototypes as our GitHubClient.
  3. Implement schemas for the new providers, so that once ran through normalizr(), their data structure match the data structure of GitHub entities.
  4. Impement OAuth / Providers settings
  5. Enjoy having the most powerful open source client out there 🎉
housseindjirdeh commented 6 years ago

This is SO SO SO great.

toronto raptors applause gif-downsized_large

It's funny, because I was having a discussion earlier with someone discussing the possibility to include GitLab/BitBucket functionality and although it's something down the line - with this thoughtful refactoring it's beyond possible (even though it's only 1 of the MANY reasons why these changes are going to be so useful). And it's all thanks to you mate 🎉 .

Thank you so much for writing this. We can send this link to anyone who we'll need to explain the architecture to.