commons-app / apps-android-commons

The Wikimedia Commons Android app allows users to upload pictures from their Android phone/tablet to Wikimedia Commons
https://commons-app.github.io/
Apache License 2.0
1.03k stars 1.23k forks source link

Reduce complexity - refactor existing code to use unified APIs #1863

Closed misaochan closed 4 years ago

misaochan commented 6 years ago

As posted by @dbrant at #1489 :

I generally like to encourage a greater emphasis on QA, continual dogfooding, and reducing complexity (i.e. refactoring existing code to use unified APIs), rather than adding further complexity just for the purpose of capturing more detailed logs in the field. Based on a quick glance at the current state of the Commons app, it looks like there's a rather high amount of complexity and dependencies (to the point of requiring multidex? 😮)

For example, for the purpose of displaying images, you seem to be using Fresco and Glide and Picasso in different places, literally all three major competing image libraries for Android. This introduces a huge amount of bloat, as well as a threefold increase in the surface area for bugs to occur. Not to derail this particular thread, but my earnest recommendation would be to take a step back, establish some best practices for the architecture of the product, and work towards refactoring all of the code to adhere to each of these best practices, one at a time.

For instance:

Decide on a single image library (e.g. Fresco) and use it throughout the app. Decide whether to use RxAndroid or plain AsyncTasks, and use them consistently (preferably RxAndroid), but don't use both. Stop using the long-deprecated org.mediawiki:api library, and use Retrofit (with RxAndroid) for your network calls. Evaluate whether you really need all the third-party components and libraries that you're depending on. They are all potential sources of bugs. (For example fr.avianey.com.viewpagerindicator or in.yuvi:http.fluent, both of which have been abandoned for six years) Try not to use third-party libraries that promise to "simplify" things, like a library that "simplifies" populating a RecyclerView, or a library that "simplifies" asking for runtime permissions. They are all sources of bugs, which are out of your control. Explain these best practices to newcomer volunteers, and reject pull requests that increase complexity unnecessarily. Once you do this, the bugs that seem puzzling today will become more and more obvious, or will simply disappear automatically. Sorry for the long-windedness (and apologies if I'm overstepping), and let me know if I can help in any way.

This makes a lot of sense, thanks! I agree that we really do need to sit down and have a discussion about pruning our dependencies. We tend to allow volunteers to add libraries as long as it doesn't introduce any bugs at the time of testing or increase the APK size too much, but indeed we should probably tighten up on that if we want to have a more polished app, due to the increased maintenance required and the increased potential for bugs down the road. An overhaul of the legacy code is also certainly needed.

I would like to introduce this refactoring into our plans for 2019. :) However, we still need to talk about what exactly we want to prune, why we are pruning it, and how to go about it. So, I would invite everyone to chime in with their thoughts on:

  1. Which libraries do you think we can remove? In cases of redundancy, which library would you recommend we use over the others and why?
  2. What sort of guidelines should we use to determine whether a new library should be added or not, in the future?
  3. What other refactoring do you think we urgently need to do?

Once we arrive at a consensus, I can draft this into our 2019 plans.

@maskaravivek @neslihanturan @nicolas-raoul @whym @psh

sivaraam commented 6 years ago

What sort of guidelines should we use to determine whether a new library should be added or not, in the future?

I guess that's not difficult. Avoid any library that can be. IOW, become dependent on a library only if we cannot reasonably work around the problem without the library and the user experience becomes terrible.

Of course these are just my opinions. Correct me if I'm wrong.

nicolas-raoul commented 6 years ago

Redundancy is unquestionably bad, we all agree about this already.

The app size is definitely important as many of our users are on slow networks.

But there are things that we should not implement ourselves, for instance image recognition features.

Runtime permissions strikes me as a typical example of an area where a popular library can drastically reduce the amount of code, bugs and maintenance on our side.

maskaravivek commented 6 years ago

Moreover, proper usage of proguard can considerably help in reducing the bloating caused by a particular library.

dbrant commented 6 years ago

Hey all, to follow up on the initial comments, here are some additional thoughts, questions, and points for discussion:

Regarding other unnecessary libraries:

Other minor points:

nicolas-raoul commented 6 years ago

Getting rid of legacy HTTP APIs would be a wonderful thing! If we are lucky that might even solve https://github.com/commons-app/apps-android-commons/issues/1866? :-)

misaochan commented 6 years ago

Thanks again for the detailed analysis @dbrant . :)

Now that some of the excess complexity will be removed by #1859, I would strongly recommend prioritizing the elimination of the woefully outdated mediawiki:api library and replacing it with Retrofit, using the json API, coupled with RxJava (This will also remove the need for the outdated yuvi:http.fluent and org.apache.http.legacy libraries if I'm not mistaken). I see you have an open pull request where a volunteer takes some first steps towards this refactor, but the volunteer seems to have dropped off. If you like, I could take it the rest of the way, as part of my 10% time at work. ;)

This would be wonderful if possible, thank you! The mediawiki:api and org.apache.http librares have been the cause of quite a few bugs indeed.

I agree with most of the other points, too. However, while I was initially dubious about Dagger, when I got around to using it I personally did feel like it helped simplify the creation of a shared model, rather than using SharedPreferences to pass data around. But it is true that Dagger did cause its own share of problems, and in any case we should certainly have prioritized the overhaul of legacy code first.

Based on this discussion, I would like to propose an answer to my own question "What sort of guidelines should we use to determine whether a new library should be added or not, in the future?":

The main concern with these guidelines is that it will take a bit more work, and also take a longer time, for PRs by volunteers to be merged. Currently we already do take a fairly long time to merge volunteer PRs, because only one of us (@neslihanturan ) is tasked with testing and reviewing PRs as part of their job role, and she has other tasks to handle as well. But I think that the slight additional wait will be more than worth the improvement to our codebase.

sivaraam commented 6 years ago

But I think that the slight additional wait will be more than worth the improvement to our codebase.

May be we the volunteers should be made known about the limited amount of resources to review their PRs in some place? Possibly in the CONTRIBUTING.md file?

This might help them realised the reason for the delay (if they haven't figured it out correctly.

sivaraam commented 6 years ago

Based on this discussion, I would like to propose an answer to my own question "What sort of guidelines should we use to determine whether a new library should be added or not, in the future?":

Now that you have an answer, it might worth documenting it somewhere. Not sure where. Maybe in a Coding guidelines document?

misaochan commented 6 years ago

Done, see https://github.com/commons-app/apps-android-commons/wiki/Code-style#new-libraries and https://github.com/commons-app/apps-android-commons/wiki/Project-maintenance

dbrant commented 6 years ago

Here is the current plan from our end: Within the next few weeks, in the Wikipedia app we will work on isolating our network layer from the rest of the app, so that we could package it as a standalone library, basically an official successor to the mediawiki:api library, to be usable by your app as well as ours.

It will provide a superset of the API calls used by our respective apps, along with numerous convenience functions (e.g. formatting dates, GeoIP, etc), which will minimize code duplication between our products. It will also use all the latest best practices, including Retrofit, and outputting Observable objects.

Once this is done, I will contribute towards reworking the Commons app code to make use of the new library, which will hopefully trim away a lot of duplicate code, and increase both of our teams' speed and confidence when adding new features.

misaochan commented 6 years ago

That would be fantastic! Looking forward to it. :)

maskaravivek commented 6 years ago

Really excited about it. :)

misaochan commented 5 years ago

Hi @dbrant ,

In our plans for next year, we would like to prioritize replacing all usages of the deprecated org.mediawiki:api library with Retrofit (plus RxAndroid) for network calls. Is there any news of the standalone network library from the Wikipedia app that you mentioned? I would like to add this task to our 2019 PG proposal, and was wondering if we will be able to use your new library for this purpose.

dbrant commented 5 years ago

@misaochan Yes, this library is still very much in the works, and should be available soon to be used by other apps. It would definitely make sense to add it to the proposal.