ReactiveX / RxAndroid

RxJava bindings for Android
Apache License 2.0
19.88k stars 2.95k forks source link

Library Modularization via Specialization #172

Closed JakeWharton closed 9 years ago

JakeWharton commented 9 years ago

In an effort to stave off becoming either obsolete or a dumping ground (or both), a few of us have been talking through other channels about how best to approach the future of this library.

Everyone agrees that the current project is a dumping ground of utilities, operators, and helpers that were once useful to one or more people when working with RxJava on Android. These were contributed by a wide variety of people with little thought to what this library's identity would be—they just wanted to share useful code.

Android is an entire platform with vast APIs. Adapting or shimming all of its APIs with RxJava will result in a large, slow moving monolithic library. It would be very hard to dictate policy on naming, reference holding, and behavior across such a large adaptation. And finally, the ways with which developers interact with this large API surface area differs based on use-case, history, and opinion.

It is infeasible to build a single RxAndroid library.

This should come as no surprise as the repo currently doesn't even house a single RxAndroid library. The ill-defined 'framework' module splits functionality in an pre-emptive realization of all the points from above.

I am proposing a from-scratch, modularization of the library into re-usable and composeable modules. A few other notable contributors are in support of this and I'll let them voice their support, suggestions, and/or issues individually.

The APIs in RxAndroid which are fundamental to all RxJava use on the platform deals with threading. Android's hallowed main thread and the related handler-scheduler adapter are fundamental to all RxJava use in a non-trivial capacity. These will be part of the 'core' module.

The newly added plugin hooks are also something foundational with which other modules would leverage functionality. They will also be present in the 'core' module.

Finally, internal static helpers which will be used in all modules (such as the current preconditions/assertions classes) will be in the 'core' to reduce needless duplication.

The second subject on which I want to dedicate a module is binding to and from the UI controls which make up the android.view.* and android.widget.* packages. This 'ui' module will feature observable factories for listening to UI changes and action factories for subscribing UI properties.

The scope of this second module is too large for this issue as there are a lot of considerations to be made around naming, threading, reference keeping, etc. so I will create another issue for that once consensus is reached.

I'll try to preempt answers to some questions below:

This seems drastic. Is this really needed?

It has become very clear to the few of us that have been having conversations that this project is dying. If we do not undertake an effort to make drastic changes such that applications and libraries can confidently depend on it in a way that's useful to everyone then it will simply stagnate into uselessness.

The current offering covers Android APIs randomly, has varying implementations of correctness and efficient, and without a strong idea of an identity no one know what should go in.

Will this be done in an API-compatible way?

No. This will be invasive and destructive. Things will be moving.

What about deprecations?

No. There is no point. We can release master as a v0.25 which can be considered an instant deprecation of every API.

Why from scratch?

This will allow front-loading discussions about naming conventions, implementation patterns, and nuances of things like references. It's much easier to evolve an approach used by all APIs than try to unify 10 different approaches. This does not mean that the existing code will be ignored. It might even be copied verbatim in places, just that it will be all new modules with consistency.

What about activity/fragment lifecycle binding?

That'll potentially be a third module. I personally don't use these so while they are not included in this issue, they will likely be scoped to the same effort.

What about (insert API not mentioned)?

Plan for it to disappear. Copy/paste its implementation into your source tree for continued use after modularization happens. There are plenty of APIs from this library that are used which are useful but have questionable applicability to the masses. If it's specialized enough, consider making a separate library on your personal or corporate GitHub account and depend on one of the modules we will be creating. The point of having small, composeable modules is for a la carte re-use across many libraries.

When will this happen?

If no compelling, well-reasoned, and majorly agreed-upon counter-argument to this approach is to be had we would like to start figuring out the 'core' module in one week. The final current-form release of the library as-is will happen in approximately the same timeline. Once the 'core' module is mostly agreed upon, implementation will start and discussion around the 'ui' module will begin (and will likely be a longer process to flesh out).

How can I help?

Get on board with the effort. Constructive comments, criticisms, and suggestions are welcome. Don't "+1" this issue (we'll see how many read this far). The easiest way to think about this effort is as a new, opinionated, well-designed library driven by a few people who really want it to succeed both in terms of usability to developers but also in being clear in what's appropriate and what's not appropriate for inclusion.

erickok commented 9 years ago

I strongly agree with the separation into modules, as developers can pick themselves which parts to use. The only counter-argument can can think of is that most developers would use most modules anyway, in which case the split might not be as useful, but it wouldn't do much harm (code duplication) either.

I foresee a (4th?) separate module for compat-ui, which contains bindings like the ui module, yet for AppCompat classes. This would actually be another argument FOR the separation of code, as its dependency on appcompat could be restricted to actual users of it. (The same goes perhaps for the Android Design Support Library.)

I have been following the NotRxAndroid project and like the stronger consistency of the API and implementation. For future contributions I would hope to have an even stronger guideline. I have wanted to contribute but as every implementation seems to differ it is hard to fall in line with the correct style. For example, some view bindings allow broadcasting of the initial value and some not. Some allow multiple bindings (via an internal list of listeners) and some not. Would a binding emit the raw events or perhaps the objects that are affected?

mttkay commented 9 years ago

+1 all of what Jake said. From my personal standpoint, the project had already derailed just a few weeks after it broke out of RxJava, hence my early withdrawal from it. The vast majority of contributions that had happened since were dealing with bringing RxJava into Android presentation land, and at SoundCloud we neither do or want to use RxJava anywhere in the presentation layer other than presenters being downstream subscribers to the business logic. So I’m very strongly +1 on having a core module that sheds off all of this stuff and puts it in a separate module.

I would also vote for not having things like LifeCycleObservable in the core module. That to me is framework territory, and here we deliberately decided to solve the same problem in a much simpler and straight forward way (our presenters attach/detach the model via subscriptions, but the orchestration is done automatically via an annotation based life-cycle dispatcher for less brittleness). So I would prefer to see this as an optional thing, too.

On Tue, Jun 9, 2015 at 10:28 AM, Eric Kok notifications@github.com wrote:

I strongly agree with the separation into modules, as developers can pick themselves which parts to use. The only counter-argument can can think of is that most developers would use most modules anyway, in which case the split might not be as useful, but it wouldn't do much harm (code duplication) either.

I foresee a (4th?) separate module for compat-ui, which contains bindings like the ui module, yet for AppCompat classes. This would actually be another argument FOR the separation of code, as its dependency on appcompat could be restricted to actual users of it. (The same goes perhaps for the Android Design Support Library.)

I have been following the NotRxAndroid project and like the stronger consistency of the API and implementation. For future contributions I would hope to have an even stronger guideline. I have wanted to contribute but as every implementation seems to differ it is hard to fall in line with the correct style. For example, some view bindings allow broadcasting of the initial value and some not. Some allow multiple bindings (via an internal list of listeners) and some not. Would a binding emit the raw events or perhaps the objects that are affected?

— Reply to this email directly or view it on GitHub https://github.com/ReactiveX/RxAndroid/issues/172#issuecomment-110274950 .

Matthias Käppler

Engineer

Twitter: https://twitter.com/mttkay

Skype: matthias-sc

SoundCloud Ltd. | Rheinsberger Str. 76/77, 10115 Berlin, Germany | +49 (0)172 2345679

Managing Director: Alexander Ljung | Incorporated in England & Wales with Company No. 6343600 | Local Branch Office | AG Charlottenburg | HRB 110657B

Capture and share your music & audio on SoundCloud http://soundcloud.com/creators

loganj commented 9 years ago

Ship a rev of the core first. Just schedulers, plugins, a few helpers. That opens up experimentation in UI and lifecycle libraries. It wouldn't be surprising to see multiple perfectly valid competing and complementary libraries in those spaces.

zsiegel commented 9 years ago

Agree with the comments so far. I would propose just releasing and maintaining a core module for now.

Maintaining a UI and/or framework module would be cumbersome and as Logan stated I think we can let others create libraries for this and see what shakes out. I unfortunately had to bow out helping refactor the sample app due to all of the framework level contributions.

Looking forward to the new direction.

dlew commented 9 years ago

I'm a big fan of this idea. There's no reason to have a single monolithic library when it's easy to add multiple dependencies. The current offerings are a scattershot of ideas with weak cohesion.

By creating a focused core library, we make it easier for others to build on top of RxAndroid. If someone, for example, wants to build an RxAndroidDialog, they could get started with core and build on top of it. This project could move separately from core RxAndroid, so it would have more freedom. In other words, there's no need for non-core functionality to be part of RxAndroid proper.

ronshapiro commented 9 years ago

I think this makes a lot of sense, but I also think that it makes the startup cost of someone new to Rx incorporating the code in their project. Discovering what classes and options becomes harder, especially if you just start out with core and then never find out that their are other modules. I'm not sure the feasibility of this, but I think it would be good to export one combined artifact for people to depend on for debug (if they choose), which would allow for their IDE to index everything all at once. Then, for release they could only compile the modules they needed.

I'm also wary that just simply splitting everything up into modules will really solve the problem at hand. If there was one 'ui' module, that itself would probably become bloated itself since there are so many widgets in the sdk. So one option would be to go module crazy and let people depend on whichever ones they need, but I think this creates a lot of friction for developers to manage. This split does allow people to easily not use any of the ui module and all of core, but I think the same experience could happen in the 'ui' module as is currently happening.

If many worthwhile libraries spin up that all depend on core, but are external to this repo, it may get hard to keep everything in sync, but I think it's probably a problem worth solving. Just wanted to throw it out there.

Takhion commented 9 years ago

+1–oh wait

Seriously though, I approve and applaude the effort, I believe a well though foundation and "extension framework" will not only make everything more stable, but actually faster to move forward.

A list of all associated plugins could still be collected here to make them easily discoverable, maybe through some sort of wizard/configurator; at that point adding a few lines in Gradle won't be a big deal!

frapontillo commented 9 years ago

It goes without saying, this is the only way to make RxAndroid work. About modules depending on core, you may create a RxAndroid organization and mirror all of the "unofficial-but-good" modules in order to advertise them, or even propose to take ownership of them in the org context.

cantrowitz commented 9 years ago

Happy to follow the lead on this. Just a question about this:

Finally, internal static helpers which will be used in all modules (such as the current preconditions/assertions classes) will be in the 'core' to reduce needless duplication.

If at all possible, I would prefer to standardize on Google's support annotations instead of Assertions.assertUiThread(). I realize this might not be possible in all cases, but the annotations (e.g., @UiThread) make it faster and easier to do the right thing for most developers. If you don't think this is the appropriate or is too much overhead to include the library, that's fine too!

JakeWharton commented 9 years ago

I'm pretty certain that the static analysis tools are not going to be powerful enough to understand RxJava's scheduler mechanism for moving between threads to accurately prevent people from doing the wrong thing. The use of that helper method is for the thread on which subscription happens, not the thread on which the static factory method is called.

austynmahoney commented 9 years ago

I like the idea of separating the functionality into modules. If the core module is designed well, someone should be able to create whatever they would like in their own repo as a another module. I'd love to see most of the work on RxAndroid to be done here, but as we have already experienced, everyone has different opinions on how to solve the non-core issues.

As someone else posted above, eventually I'd hope we can sort out what modules are useful/popular, and move them into an RxAndroid organization.

For those of us that would like to participate more closely, what other channels are being used for discussion?

xorgate commented 9 years ago

What's the status of this?

Should I get worried about this library falling out of date with RxJava and if so, how can I keep up-to-date?

Are new library projects already up?

JakeWharton commented 9 years ago

This is done and will be released in the next two weeks. There is nothing to fall out-of-date with on RxJava.