Skip to content
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

Optimise shops page: Only inject distributors with active order cycles #12827

Merged

Conversation

johansenja
Copy link
Contributor

@johansenja johansenja commented Aug 29, 2024

What? Why?

This follows on from some of my previous changes, to optimise the load time for the /shops page (esp. the UK instance).

When looking at the html on the https://openfoodnetwork.org.uk/shops page, I could see that >4000 shops are being injected - but only a few dozen (tops) are displayed as open and active; there are client-side filters which filter all of them to pick out the active ones (active.js.coffee/closed_shops.js.coffee). From what I can work out, the rest of the shops are superfluous because the closed shops are fetched via API (#5156).

The active attribute (as read by the filters on the front end) is determined by:

    def active
      options[:data].active_distributor_ids&.include? object.id
    end

where active_distributor_ids is determined by:

    def active_distributor_ids
      @active_distributor_ids ||=
        begin
          enterprises = Enterprise.distributors_with_active_order_cycles.ready_for_checkout
          enterprises = enterprises.where(id: @enterprise_ids) if @enterprise_ids.present?
          enterprises.pluck(:id)
        end
    end

so it seems logical to me to move distributors_with_active_order_cycles into the open_shops method, because it's the same logic that will be used to filter the open shops, but just doing it sooner on the back end rather than client-side.

What should we test?

  • Visit /shops
  • Check that the expected open shops are listed
  • Check that the filters are displayed and working as before
  • Click on "Show closed shops"
  • Check that the expected closed shops load ok

ShopsListService#open_shops is only used on this page, so it shouldn't have any other knock-on effects

Release notes

Changelog Category (reviewers may add a label for the release notes):

  • Technical changes only

Dependencies

Documentation updates

@johansenja johansenja changed the title Only inject distributors with active order cycles into shops page Optimise shops page: Only inject distributors with active order cycles into HTML Aug 29, 2024
@johansenja johansenja changed the title Optimise shops page: Only inject distributors with active order cycles into HTML Optimise shops page: Only inject distributors with active order cycles Aug 29, 2024
@sigmundpetersen
Copy link
Contributor

Hi @johansenja , there are some build failures here that seem relevant.
We have also merged some fixes to the build recently, so you could rebase to get a cleaner build 👍

@johansenja johansenja force-pushed the only-fetch-active-open-shops branch 3 times, most recently from 537eba8 to ae7d433 Compare September 3, 2024 16:43
@@ -32,10 +32,19 @@
end

describe "#closed_shops" do
let!(:hub_open_order_cycle) {
Copy link
Contributor Author

@johansenja johansenja Sep 3, 2024

Choose a reason for hiding this comment

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

Without this, techinically none of the shops in this test are open & active (as in, visible in the "open shops" on the /shops page)

@johansenja
Copy link
Contributor Author

johansenja commented Sep 3, 2024

Hi johansenja , there are some build failures here that seem relevant.
We have also merged some fixes to the build recently, so you could rebase to get a cleaner build 👍

Thanks for the heads-up! Looks l missed some cases but I'm hoping it should be a bit more comprehensive now 🤞🏻

@sigmundpetersen
Copy link
Contributor

Yes looks good now.
Simplecov is failing but that is also in master. Maybe you want to have a look at that as well in another PR? :)

@johansenja
Copy link
Contributor Author

I hadn't noticed that previously, but I am hoping #12839 should cover it!

@rioug rioug self-requested a review September 3, 2024 23:22
Copy link
Collaborator

@rioug rioug left a comment

Choose a reason for hiding this comment

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

Looks good ! thanks @johansenja 🙏

So now that we are doing the filtering in the backend, do you think we could remove it from the front end ?

def closed_shops
shops_list.not_ready_for_checkout.all
shops_list.where.not(id: open_shops.reselect("enterprises.id"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

TIL about reselect

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🙌🏻 It can be very useful! There is also rewhere, reorder and regroup, though I don't use them so much

Comment on lines +6 to +8
shops_list.
ready_for_checkout.
distributors_with_active_order_cycles
Copy link
Collaborator

Choose a reason for hiding this comment

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

I noticed in active_distributor_ids we do the filtering with order cycle first and then we filter for ready for check out, extract from the method :

enterprises = Enterprise.distributors_with_active_order_cycles.ready_for_checkout

Any reason you are doing it the other way around here ? I don't think it matters by maybe one is more efficient than the other ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This wasn't an intential choice, but it shouldn't matter too much when it comes to querying the DB because it only affects the order of some of the wheres and joins - and postgres should be smart enough to plan and execute both queries in the same way. On the application side, I think any differences would be marginal

@rioug rioug added the technical changes only These pull requests do not contain user facing changes and are grouped in release notes label Sep 3, 2024
Copy link
Member

@mkllnk mkllnk left a comment

Choose a reason for hiding this comment

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

Thank you.

I added some comments but changes are optional.

We should add to the test list though to check that all filters display correctly. We had bugs around that before when working on the shops list.

Comment on lines +32 to +34
open_enterprise_ids = Enterprise.distributors_with_active_order_cycles.pluck(:id).to_set
expect(open_enterprise_ids).not_to be_empty
expect(shops.pluck(:id)).to all be_in open_enterprise_ids
Copy link
Member

Choose a reason for hiding this comment

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

It's good to cover the code but the expectation doesn't achieve much. If you call Enterprise.distributors_with_active_order_cycles in the spec and in the code under test and check if they equal then the test will always pass. A better test would be to manually select the enterprise ids from your test data.

So I guess that distributors[0] was chosen to have an order cycle here. Reading the spec, I would expect that id to be returned. Can we check that in the spec?

open_enterprise_ids = Enterprise.distributors_with_active_order_cycles.pluck(:id).to_set
expect(open_enterprise_ids).not_to be_empty

shops.pluck(:id).each do |shop_id|
Copy link
Member

Choose a reason for hiding this comment

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

Here I would find it much clearer to state something like expect(shops).to eq distributors[1..2].

Comment on lines 5 to 8
shops_list.ready_for_checkout.all
shops_list.
ready_for_checkout.
distributors_with_active_order_cycles.
all
Copy link
Member

Choose a reason for hiding this comment

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

You are showing nice TDD here. While I find that super helpful in development, I think that the spec and the changed code can be in the same commit. Then a reviewer can see straight away which spec is passing for this new code.

Another guideline is to make specs always pass in the commit history. This enables us to run git bisect on a failing spec to see when it started failing. So if you want to commit your spec first, and that's totally legit as well, then you need to declare the spec pending first, so that it doesn't fail. Then when you implement the code, you remove the pending to make it pass properly. That way you clearly mark the spec as now fulfilled with your code change. Sometimes you need several commits to actually make a spec pass and this way you are transparent about when it's done.

Does that make sense to you?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that makes sense - I must say I don't often use pending but it definitely makes sense for cases like this

@drummer83 drummer83 self-assigned this Sep 5, 2024
@drummer83 drummer83 added the pr-staged-au staging.openfoodnetwork.org.au label Sep 5, 2024
@drummer83
Copy link
Contributor

Hi @johansenja,
Thanks for continuing your work on this! 💪

I have tested your PR on our staging AU server and it's working well:

  • Open shops are loading correctly. ✔️
    image

  • Product category filters are working. ✔️
    image

  • Shipping methods filters are working. ✔️
    image

  • Search (shop name, town, etc.) is working. ✔️
    image

  • Closed shops are loading correctly. ✔️
    Note: Closed shops are displayed in a different (random?) order - it's not a big deal, I think.
    image

Other findings

Product categories of closed shops

The displayed filters for type/product category show many blank spaces when closed shops are listed. I assume those are placeholders for categories from the closed shops, which can't load the category name properly.
This was NOT introduced by this PR. We have it in current master as well. However, maybe it was introduced by one of your earlier PRs? I'm absolutely not sure, maybe it has always been there, but if you could check, I think this would be great! 🙏
image

Inconsistent product categories

The available filters show more product categories than the available shops. I assume that the filters is checking for ALL product categories in use by that shop, while for the shop only the ones in an active order cycle are considered. This can be confusing to customers. I don't think this was introduced by any of your PRs, just mentioning it here because I came across this for the first time. I will create a separate issue for this and check with product what's the desired behavior.
image

Conclusion

My findings have not been introduced by this PR. All test cases passed successfully.
This one is ready to go! Merging! 🚀
Thanks again for your great contributions! 🥳

@drummer83 drummer83 merged commit cf21c03 into openfoodfoundation:master Sep 5, 2024
53 checks passed
@drummer83 drummer83 removed the pr-staged-au staging.openfoodnetwork.org.au label Sep 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
technical changes only These pull requests do not contain user facing changes and are grouped in release notes
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

5 participants