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

CSHARP-3985: Support multiple SerializerRegistries #1592

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

papafe
Copy link
Contributor

@papafe papafe commented Jan 13, 2025

/// <summary>
/// //TODO
/// </summary>
public interface IBsonSerializationDomain
Copy link
Member

@sanych-sun sanych-sun Jan 14, 2025

Choose a reason for hiding this comment

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

Why do we need such super-interface? It has everything in it: configuration, resolving and even reading/writing. Is there any use case when one need all of this together? I would prefer to use 3 separate interfaces: IBsonSerializationBuilder (or similar, to contain everything related to configuration, registration) - when one done with configuration - can call Build method and get IBsonSerializerRegistry (+ we might want to make IBsonSerializerRegistry as readonly for lookup only) and finally there is IBsonSerializer (to contain Serialize-Deserialize methods). So we will separate all use-cases: for application bootstrap/configuration - one have to use IBsonSerializationBuilder, in run-time to resolve the serializer - IBsonSerializerRegistry should be used, and finally to read/write - we have IBsonSerializer itself.

Copy link
Member

Choose a reason for hiding this comment

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

BTW, having IBsonSerializationBuilder is very well aligned with idea of having MongoClientBuilder to create MongoClients. Serialization builder could be part of the bigger MongoClientBuilder.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the main problem here is that we're trying to move away from the static super-class that is BsonSerializer without creating a breaking change. At the moment IBsonSerialisationDomain is an interface with everything that BsonSerialiser does, so that we can create an instance class that we can inject where we need. At a later time (possibly we can break this ticket in multiple PRs) this would allow developers to define custom serialization configuration for a certain mongo client/database/collection.
And I agree that this interface does a lot, but so did BsonSerializer and unfortunately it's difficult to separate everything from each other without breaking what's already there, given that almost everything is in the public API and we can't change the behaviour before a new major. For example, one of the issue we have is that the code to work with discriminators is not part of IBsonSerializerRegistry, but it's all over the place.
I feel that moving away from a static class would already be a positive change for the future, and that changing the way we do serialisation is definitely something we should do, but that would require changing the public API and a new major version.
What do you think?
Also @rstam tagging you here so you can follow the conversation 😄

Copy link
Member

Choose a reason for hiding this comment

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

I do understand that we are limited by not allowing to have a breaking changes, but if we decide to introduce a new interface(s), let's make them useful for initiatives that will follow soon. Let's discuss pros and cons of each idea with whole team.

@rstam rstam self-requested a review January 14, 2025 17:11
internal class BsonSerializationDomain : IBsonSerializationDomainInternal, IDisposable
{
// private fields
private ReaderWriterLockSlim __configLock =
Copy link
Contributor

Choose a reason for hiding this comment

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

Use a single leading underscore for instance fields (double leading underscore for static fields).


private static bool __useNullIdChecker = false;
private static bool __useZeroIdChecker = false;
private static readonly IBsonSerializationDomainInternal _domain;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use two leading underscores for static fields (single leading underscore for instance fields).

Copy link
Contributor

Choose a reason for hiding this comment

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

This field should probably be called __defaultDomain.

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, at the moment I'm not worrying too much about the code style, because I'm worried I could end up with a complete redesign in some days 😄

/// <summary>
/// //TODO
/// </summary>
IBsonCoreSerializerConfiguration SerializationConfiguration { get; }
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this property doesn't belong in this interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My idea would be that the IBsonCoreSerializer interface would contain everything that can be used to do the serialization and this also includes the configuration necessary for that.

/// <summary>
/// //TODO
/// </summary>
public interface IBsonCoreSerializer //TODO Don't like the name but have no better idea at the moment
Copy link
Contributor

Choose a reason for hiding this comment

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

I propose IBsonSerializationHelpers as the name of this interface.

/// <summary>
/// //TODO
/// </summary>
public interface IBsonCoreSerializerConfigurator
Copy link
Contributor

Choose a reason for hiding this comment

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

I propose IBsonSerializationDomainConfigurator as the name of this interface.

"Core" in the name doesn't mean anything to me.

/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <returns>A serializer for type T.</returns>
IBsonSerializer<T> LookupSerializer<T>();
Copy link
Contributor

Choose a reason for hiding this comment

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

You may have put this method here thinking it was a read-only method but because we configure serialization on demand as needed calling this method might require creating and registering a new serializer, so this method can also modify the serialization domain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ouch, need to check that

/// //TODO
/// </summary>
/// <returns></returns>
IBsonCoreSerializer BuildCoreSerializer();
Copy link
Contributor

Choose a reason for hiding this comment

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

This method makes no sense to me and isn't used either.

Copy link
Contributor Author

@papafe papafe Jan 15, 2025

Choose a reason for hiding this comment

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

This is not used at the moment, but I think this could be something that developers can use to create what now is called IBsonCoreSerializer. Once this method is called, the "domain/core serializer" is read only.
This is of course if I manage to separate completely the 3 interfaces

/// <summary>
/// Gets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered is enabled.
/// </summary>
bool UseNullIdCheckerEnabled { get; }
Copy link
Contributor

Choose a reason for hiding this comment

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

This property and the next are never used and also seem to duplicate earlier methods in a different interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea here would be that this is part of the core serializer configuration, while the others are in the configurator, this is why these ones are read only

/// <summary>
/// //TODO
/// </summary>
public interface IBsonCoreSerializerConfiguration
Copy link
Contributor

Choose a reason for hiding this comment

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

One hard part about trying to split up the single interface into smaller interface is that they sometimes end up with colliding names.

I would say this interface should maybe be called IBsonSerializationDomain but that's the name of the single bundled interface and I certainly don't want to change that one.

I propose IBsonSerializationDomainRegistry as the name for this interface.

I'm actually on the fence whether splitting the bundled interface into three is even worth it, given that we expect to massively redesign how serialization is configured in 4.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm also on the fence with it, but I think I could spend a little bit more time to see if this is something possible, or it would be too complicated for now.
It could also be a stepping stone for what we do in 4.0, otherwise we could end up making so many changes in the API and alienate users maybe?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants