Repository Pattern

More often than not, I reach for the repository pattern when I'm writing a client app for a server-based application.

The problem it solves: Keeping data consistent across an app without requiring a network request each time that data is displayed.

Example of problem: Say you have an app with two screens: a list of articles screen and the single article screen. Both screens have a πŸ‘ button that shows how many people have πŸ‘β€™d the article.

Parts that go in the pattern:

How It Works

The user interface:

When implementing a piece of UI that needs data from the API, let that piece of UI fetch it from a repository.

ThumbButton {
  articleID = "abc123"
  repository = /* ... */

  render() {
    return "πŸ‘ <<repository.thumbCountFor(articleID)>>"
  }
}

To keep the displayed data up to date, have the UI listen for changes from the repository and update itself if anything changes.

ThumbButton {
  start() {
    repository.listenForChange(handleRepositoryUpdated)
  }

  end() {
    repository.stopListeningForChange(handleRepositoryUpdated)
  }

  handleRepositoryUpdated() {
    this.rerender()
    // The data will be refetched from the repository on the next
    // render.
  }
}

The network data source:

ThumbNetworkDataSource {
  thumbCount(articleID) {
    return network.thumbCount(articleID)
  }

  addThumb(articleID) {
    network.addThumb(articleID)
  }
}

The local data source:

ThumbLocalDataSource {
  thumbCounts = {:}  // an empty mapping
}
ThumbLocalDataSource {
  thumbCount(articleID) {
    return network.thumbCount(articleID)
  }

  setThumbCount(articleID, thumbCount) {
    thumbCounts[articleID] = thumbCount
    this.notifyListeners()
  }
}

The repository:

At this point, the repository's responsibilities are much clearer: