java-manta
java-manta copied to clipboard
clarify version stability and api surface area
From the CHANGELOG "this project aims to adhere to Semantic Versioning". However, that leaves open the questions of what exactly the public api is. Is it all classes that happened to be public? All classes exposed via MantaClient? Everything a "reasonable user" would use? We will also sometimes haphazardly have documentation that say a whole module (ie benchmarks) is not a stable public contract.
This has come up with reviews where we have reasonable through how each class is exposed. That easy to mess up and unfun to repeat on each review. As this library is used more it becomes harder to make the kind of sweeping changes we did in 3.0.0, so we need to create space for organic growth.
In java-http-signature we have deprecated a significant number of methods, but not yet had a release that removed them. java-manta is significantly larger with (as of this writing) 131 non-test classes in the primary module.
Some related approaches:
- https://illumos.org/man/5/attributes
- https://cwiki.apache.org/confluence/display/FLINK/Stability+Annotations
- https://github.com/google/guava/wiki/PhilosophyExplained (Notably
@Beta) - This hadoop thing: https://hadoop.apache.org/docs/r2.7.1/api/org/apache/hadoop/classification/InterfaceAudience.html
Proposal:
- Add a
@Publicannotation to the classes that form the public consumed API of the application. For example,MantaClientand exceptions. I am unsure of the merits of also having an@Internalannotation, and thus mandating that every class have an annotation. I think I lean slightly towards having both so it is harder for developers to make a mistake. - Next time we add a significant new feature that is likely to evolve (like the jobs multi-part upload) we should
@Betait (or something like that). - Sometime soon (after MPU is "officially" available?), we should take a pass at deprecating warts in 3.x java-manta.
- If needed use we should totally use
@VisibleForTestingor similar. - Add a note to the readme on which modules are internal, even if obvious (benchmarks).
NOTE: @Stable will likely be an (internal?) jdk9 annotation, so that might not be the best word choice.
Having been on the implementing side for years, I would assume that anything that is public has an assumption of stability from an API contract standpoint. However, if you are incrementing minor versions, there is an expectation that the behavior may subtly change. With major version changes, the expectation is that some portion of the API will change, but not like 80%. One should be able to catch major version incompatibilities via compilation errors.
I would assume that anything that is public has an assumption of stability from an API contract standpoint
As a consumer of libraries that is my expectation as well. If the class is public then I can use it. I'll even extend java.lang.String if I want to!
But as library developer, I would not want people to depend on com.joyent.manta.util.ConcurrentWeakIdentityHashMap or com.joyent.manta.client.multipart.EncryptionState.
https://docs.google.com/spreadsheets/d/1lly891zfckkYJfV6nfbBvC2flFsUu9Nya2bqF7F07zw/edit#
I went class by class and took a stab at what this might look like. I think my largest take away was just how broad the api surface area is.
(I think I now lean slightly towards having an @Internal and letting public classes just be public like anyone would assume by default.)
Is the primary issue here that there are classes which should be package-private but need to be public to work across package boundaries?
An annotation for such classes might be valuable but I'd be hesitant to add annotations to every class that reaffirming that the class is public (and doing so indefinitely for every new class) without a clear benefit.
Is the primary issue here that there are classes which should be package-private but need to be public to work across package boundaries?
Yes I think that's a good way to put it. I at least have the habit of typing public by default, so it is also possible that some of those "Internal" classes could be package-private.