Skip to content

Refactor IndexBackfiller constructor #3797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 13, 2022

Conversation

tom-andersen
Copy link
Contributor

No description provided.

@tom-andersen tom-andersen requested a review from wu-hui June 8, 2022 22:01
@tom-andersen tom-andersen marked this pull request as ready for review June 8, 2022 22:01
@google-oss-bot
Copy link
Contributor

google-oss-bot commented Jun 8, 2022

Coverage Report 1

Affected Products

  • firebase-firestore

    Overall coverage changed from 46.03% (a283019) to 46.02% (01a54ca) by -0.01%.

    FilenameBase (a283019)Merge (01a54ca)Diff
    Assert.java57.14%60.00%+2.86%
    DeleteMutation.java95.24%90.48%-4.76%
    IndexBackfiller.java78.69%79.69%+1.00%
    LocalStore.java99.38%99.37%-0.00%
    SetMutation.java97.22%94.44%-2.78%

Test Logs

Notes

  • Commit (01a54ca) is created by Prow via merging PR base commit (a283019) and head commit (5b8309b).
  • Run gradle <product>:checkCoverage to produce HTML coverage reports locally. After gradle commands finished, report files can be found under <product-build-dir>/reports/jacoco/.

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/eLoEBa27Y0.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Jun 8, 2022

Size Report 1

Affected Products

  • firebase-firestore

    TypeBase (a283019)Merge (01a54ca)Diff
    aar1.26 MB1.26 MB+509 B (+0.0%)
    apk (release)3.39 MB3.39 MB+316 B (+0.0%)

Test Logs

Notes

  • Commit (01a54ca) is created by Prow via merging PR base commit (a283019) and head commit (5b8309b).

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/2DK2kYLizD.html

Copy link
Contributor

@ehsannas ehsannas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great. Good job identifying this. One minor nit pointed out below.

* is null an AssertionError will be thrown. The string messageFormat will be formatted with the
* provided args using {@link String#format(String, Object...)}.
*
* @param obj The condition to check
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @param obj The object to be compared with null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

@wu-hui wu-hui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great refactor, I still want to avoid mocking local store however..

backfiller = new IndexBackfiller(persistence, new AsyncQueue());
backfiller.setIndexManager(indexManager);
backfiller.setLocalDocumentsView(localDocumentsView);
LocalStore localStore = mock(LocalStore.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still a bit hang up on the fact that local store is no longer final because we need to mock it.

It seems QueryEngine depends on IndexManager and LocalDocumentsView, which we already have. Can we just create the query engine here, and use it to construct a proper local store instance?

In general, I am against introducing mocks unless there is no other way around, here it might be more hassle, but I think the end result is closer to the code that gets run in prod.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To address your concern, I created an interface UserComponents. LocalStore will implement interface, and the test can just use an anonymous implementation. This will allow LocalStore to remain final. I also think this might be a step in the right direction to separate out logic associated with user change and components. Maybe this responsibility should be moved outside LocalStore (already quite large 900 lines class)?

Copy link
Contributor Author

@tom-andersen tom-andersen Jun 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followup on offline conversation:

Instantiating LocalStore drags in too many other dependencies. From a unit test perspective, mocks were invented to solve this problem, and avoid having to instantiate the world in order to run a unit test. LocalStore is a textbook definition of something that should be mocked in unit tests.

I agree that we should strive to keep classes final. This has performance benefits, and also helps us more easily reason about our code.

Having a single implementation of an interface is not necessarily a bad thing. Consider the Dependency Inversion Principle from SOLID. The interface describes a contract between two classes. Although LocalStore offers many other methods, the interface doesn't simply repeat the public methods on the class, but instead describes a reduced set of methods required to fulfill the contract with the IndexBackfiller class. This makes the system more loosely coupled. This is exactly what was done with the BundleCallback interface as well.

That said, I have come up with another iteration. Instead of an interface, I have simply required Supplier<> parameters for IndexManager and LocalDocumentsView. Unfortunately, since create method that instantiates IndexBackfiller exists in the com.google.firebase.firestore.core package, I had to make com.google.firebase.firestore.local.LocalDocumentsView public instead of package private.

I am not sure whether this is an improvement over having an interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a thought over the weekend. I can make this work without making LocalDocumentView public by having chained constructors in IndexBackfiller.

@wu-hui wu-hui assigned tom-andersen and unassigned wu-hui Jun 10, 2022
@tom-andersen
Copy link
Contributor Author

/test smoke-tests

@tom-andersen tom-andersen assigned wu-hui and unassigned tom-andersen Jun 10, 2022
Copy link
Contributor

@wu-hui wu-hui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@wu-hui wu-hui assigned tom-andersen and unassigned wu-hui Jun 13, 2022
@tom-andersen tom-andersen merged commit fb8544c into master Jun 13, 2022
@tom-andersen tom-andersen deleted the tomandersen/refactorIndexBackfillerConstructor branch June 13, 2022 14:45
@firebase firebase locked and limited conversation to collaborators Jul 14, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants