What to publish?

I have been considering the question of what modules and struct items to make public (pub) when publishing my crate ( rustdb - an SQL database (in development) ).

A minimal interface would allow the database to be created, and queries to be executed ("Execute this string"). Almost all the internal details would be concealed.

The next level would allow extra pre-defined functions ( written in Rust ) to be made accessible to the SQL code. The interface for this is a little more complicated, although still quite small.

However, in order for the cargo doc generated documentation to be a full "maintenance manual" rather than an "owners manual", I am thinking about (a) Making all modules public (b) Not using pub(crate) anywhere (c) Making various items public where it's semi-reasonable to do so, even though they might arguably be left private.

This allows clients to potentially access the database at a lower level, and doesn't place any artificial restrictions on what is possible. It also makes it much easier to "see inside" how the crate works using the automatically generated cargo doc documentation, rather than providing a "black box" where the implementation details are hidden without looking at the source code.

The downside of course is that if internal details change in some future version, client code may need to be changed. It's unconventional. It's putting the onus of the client rather than the library to decide where to draw the interface line.

What do you think?

1 Like

If your sole purpose is to have all items documented, even private ones, then simply invoke cargo doc --document-private-items. You don't have to make something and everything public just to have it documented.

It's not; it's called the plumbing and porcelain pattern, popularized by Git. Be careful though: make sure to only expose interfaces which can't be misused. Having low-level access is nice, but your public API should remain sound no matter what.

Also, don't expect your API to be stable from the very first release. It's just not realistic. You will find bugs, you will add missing features, and as you gain experience with the domain, you will discover much better ways of doing things. Don't rush to 1.0 and stability – allow yourself quite some time to improve your code.

6 Likes

I think it's a good idea to keep public interfaces as small as possible to get the job done as advertised.

If anything is public people will use it. You then have a support nightmare as you are unable to change anything without breaking your users code.

Implementation details should be hidden. Documentation will then be smaller and more easily digestible by prospective users.

If none of that maters to you, perhaps don't publish it as a crate. Just put it up on git hub as and example or experimental code. Replete with warnings about how it may morph in the future.

1 Like

I think users generally look at examples. It isn't difficult to put warnings, "You shouldn't need to look in this module, it's subject to change, but might be useful".

The other thing is it's not easy to foresee everything that anyone might ever want to do. What I want to avoid is putting artificial barriers that stop someone accessing data or some struct at the lowest level, when that's not usually required. One thing it may be useful for is instrumentation, for example if someone wants to dive in and see what functions have been loaded/cached. I don't know why someone would want to do that, but it might conceivably be useful for some reason I haven't thought of. So why not make the dictionary a public item in the database struct? Just one example, there would be dozens if not hundreds.

My feeling is that a crate should do one thing and do it well.

Trying to cater for every possible future, unforeseen, eventuality is impossible. It implies that the crate has not been designed yet.

What benefit does the user get from having a large amorphous blob of code with a huge unstable stable, and advertised to change, API? May as well just put it on GitHub as an experiment/example and invite people to play with it.

That is what worries me :slight_smile:

Another thought, not sure if this would work, but could I use crate features to enable/disable parts of the interface? So by default you get a very minimal stable interface (say), but by enabling a feature you get access to the internal modules, which may be less stable.

Edit: yes, this does seem to be possible. By selecting the "minimal" feature, my users now get only the minimal interface. The default is (currently) "internal", which exposes more.

Do you do this with a conditional re-export (pub use)?

Not at present, but I think you could. What is nice is that when you run cargo pub (not on the library, but on the client crate), depending on the features you have selected, you get appropriate documentation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.