Tracking issue for V2
In issues #389 and #158, the need to create a V2 of the go-sdk was identified. This topic was also discussed in the biweekly community meeting on Thursday July 3, 2025.
There are several changes that I would like to see as part of a V2 (not exhaustive):
- [ ] We should also consider #350. In v2, I would like to change the signature of
openfeature.NewClientto take no parameters, and create a new function calledopenfeature.NewDomainClientthat takes a string parameter calleddomain. I want to avoid the namesopenfeature.GetClientandopenfeature.GetDomainClientas suchGetfunctions are not as common in Go andNewis more idiomatic.
Out of the list above, only number 8 and potentially number 1 (depending on how/where we introduce generics) will cause a breaking change to providers. For number 8, taking a context parameter and returning an error is small enough of a change that I think that is reasonable, especially considering that the StateHandler interface is opt-in and not required to implement.
To implement the above, I think we can actually make a lot of progress before we even create a v2 module. For example, for those identifiers that are to be renamed, we can create the target type/function and deprecate the old one. Then once v2 is created, all we need to do is delete the deprecated identifiers, making that transition a bit easier on our end.
Lastly, before we officially release V2 and deprecate V1, we will want to gather as much feedback as possible about the SDK to ensure that no further breaking changes are anticipated after V2 is released. Once it is released, we will also want to be careful going forward about adding new exported identifiers to ensure that they align with language best practices.
This API concern had breaking changes but could be considered for a v2. https://github.com/open-feature/go-sdk/issues/259
This API concern had breaking changes but could be considered for a v2. #259
@dmathieu if you don't want to handle errors there is client.Boolean.
Hey @sahidvelji ! Thanks for opening this. I was dealing with various CI issues today so I didn't have time to go through it, but I'll give it some thought on Monday. I've added a few assignee as well.
My notes, addressing each of @sahidvelji 's points:
- I'm in favor of the possibility of supporting generics for the object evaluation, and there's a few "data" objects that also could use generics (the EvaluationDetails and ResolutionDetails, and HookContext). Additionally, Hooks could be made to support generics themselves (specifying the type of the value in a hook, as in Java).
- openfeature.IEvaluation or openfeature.IClient are basically exact representations of the evaluation API global object and the client abstraction defined by the spec. I'm not sure how we can completely remove these... Are you simply talking about breaking them up into smaller interfaces? Or just changing their names?
- 💯
- 💯
- I don't feel strongly about this... one possible advantage I guess is we could, in-future, version these separably, right? I'm not sure that's a great idea though.
- 💯
- Are you suggesting just
openfeature.GetClient()then? - Agree with this one, but we should be careful to try to implement this in a way that's non-breaking to providers as @thomaspoignant and @guidobrei mentioned in the community meeting
- 💯
- Agreed, but I recommend you drop that from this list and create a new issue, even if it's a "post v2" issue.
I'd also like to add:
We could consider removing these functions entirely. They return errors directly, which add complexity and is arguably against the spec, which says evaluation methods should never abnormally terminate (returning a non-nil error in Go signals an abnormal termination equivalent to throwing IMO). People actually complained about the ergonomics of these and we implemented the non-error-returning versions in response. The "detailed" evaluation methods also return errors, and we have no "non-error" variant. We should consider our options here to make these consistent and idiomatic.
there's a few "data" objects that also could use generics (the EvaluationDetails and ResolutionDetails
This can be done cleanly without a breaking change today. Please review #403
openfeature.IEvaluation or openfeature.IClient are basically exact representations of the evaluation API global object and the client abstraction defined by the spec. I'm not sure how we can completely remove these... Are you simply talking about breaking them up into smaller interfaces? Or just changing their names?
I wouldn't mind these interfaces as much if they were unexported. Does that work? The concern is that these interfaces are way too big. Go encourages small, composable interfaces. And, generally interfaces are defined on the consumer side rather than by the producer.
Are you suggesting just openfeature.GetClient() then?
Yes, I will make that clear in my post.
Agreed, but I recommend you drop that from this list and create a new issue, even if it's a "post v2" issue.
Will do.
We could consider removing these functions entirely. They return errors directly, which add complexity and is arguably against the spec, which says evaluation methods should never abnormally terminate (returning a non-nil error in Go signals an abnorma termination equivalent to throwing IMO). People actually complained about the ergonomics of these and we implemented the non-error-returning versions in response. The "detailed" evaluation methods also return errors, and we have no "non-error" variant. We should consider our options here to make these consistent and idiomatic.
I will add that to the list for consideration.
Hey @sahidvelji, thanks for putting this together. I'm 100% in favor of a v2, but I'd like to minimize or avoid breaking changes to existing providers, if possible. Could you categorize the breaking changes list based on whether it will impact the provider or not?
@dmathieu Does @erka 's comment address your concern?
there's a few "data" objects that also could use generics (the EvaluationDetails and ResolutionDetails, and HookContext). Additionally, Hooks could be made to support generics themselves (specifying the type of the value in a hook, as in Java).
HookContext and hooks in general would be a bit tricky since methods cannot have type parameters in Go. See https://github.com/open-feature/go-sdk/issues/158#issuecomment-1836448183. I would need to dig a little deeper to determine whether it's possible. It would of course be a breaking change for Hook Authors.
Just wanted to throw in the additional support for v2.
This probably isn’t a major factor but I think an added bonus is the improving the experience of a new contributor trying to understand such a large project.
Getting tripped up on understanding the flow of the code can slow someone down or maybe give them pause on contributing (def been guilty of it😅). I feel like I can see these changes give a better experience to that initial “learn the code/project” time, and I believe that is another positive in my book.
It seems like we have consensus that a v2 is a good idea. Should we create a v2 branch or take a different approach?
@beeme1mr I'd like to get feedback from the rest of the TC first cc @kinyoklion @lukas-reining @thomaspoignant .
If majority of us are in favor, I will basically convert this issue into a parent, and create sub-issues for each point.
@beeme1mr I would actually like to delay creating the v2 module a bit given my point here:
To implement the above, I think we can actually make a lot of progress before we even create a v2 module. For example, for those identifiers that are to be renamed, we can create the target type/function and deprecate the old one. Then once v2 is created, all we need to do is delete the deprecated identifiers, making that transition a bit easier on our end.
I essentially would like to accomplish as much as possible before creating the v2 branch in order to minimize the amount of time needed to maintain two versions. There is a good bit of work that can be done now in v1 without creating breaking changes. This includes refactoring code internal to the SDK (to make certain additions/modifications easier for v2), deprecating whatever we think should not carry over to v2, as well as number 6 on my list.
I also want to emphasize that the list in my original post is not exhaustive and that there may be things I have missed. I have not looked through everything yet.
If majority of us are in favor, I will basically convert this issue into a parent, and create sub-issues for each point.
Sounds good. I think once we have the sub-issues and we're aligned on what exactly we need to do for v2, and we have finished making all the v2-related non-breaking changes, we can go ahead and actually create the v2 module to tackle the rest of the sub-issues.
Let me know if this approach makes sense.
@beeme1mr I'd like to get feedback from the rest of the TC first cc @kinyoklion @lukas-reining @thomaspoignant .
If majority of us are in favor, I will basically convert this issue into a parent, and create sub-issues for each point.
I don't have a strong opinion on most of this aside from item 2. I think removing/minimizing exported interfaces is pretty important for long-term maintainability. I do suspect though that it will also lead to an increase in issues as people coming from other languages to Go have an expectation of interfaces that they then can implement for testing or other purposes. So we need to be sure to demonstrate in some capacity how someone should use interfaces in their application and for testing. If we really want interfaces, then likely very small ones without the expectation they represent an entire API surface of the object.
Overall I think I am fine with a v2 here if people closer to the users of this SDK think that combined these items rise to the level which merits the associated disruption, or that it will be a minor enough update that it won't really be disruptive.
@kinyoklion WRT breaking changes, my impression based on what's been proposed is that consumers would be able to absorb the proposed changes relatively easily, it would entail changes such as:
- removing some return value assignments (we'd be removing
errorreturns from some older functions) - migrating from some removed methods (GetBoolean/GetInteger, -> Boolean/Integer) unless we decide to use the older
GetXxxformat as the "errorless" variants in v2 - requiring
context.contextin some invocations (SetProvider/Shutdown)
I suspect these migrations would "feel" easy; though there'd be compilation issues, you wouldn't have to do much thinking or significant refactoring to address them.
cc @sahidvelji do you agree with my subjective summary above?
cc @sahidvelji do you agree with my subjective summary above?
Generally yes. It depends a bit on how we handle introduction of generics into the SDK. I think we can mostly avoid the need for breaking changes. If not, we can also always provide additional types/interfaces that are supplementary (not replacements) to the existing types/interfaces. That way, support for generics can be opt-in where possible.
In #403 I introduced generics without a breaking change. I would have to think a bit more about where exactly we want to use and/or expose generics.
Sorry for the delay and thanks for the great summary @sahidvelji!
openfeature.IEvaluation or openfeature.IClient are basically exact representations of the evaluation API global object and the client abstraction defined by the spec. I'm not sure how we can completely remove these... Are you simply talking about breaking them up into smaller interfaces? Or just changing their names?
I wouldn't mind these interfaces as much if they were unexported. Does that work? The concern is that these interfaces are way too big. Go encourages small, composable interfaces. And, generally interfaces are defined on the consumer side rather than by the producer.
@sahidvelji is the point of this, that they are not needed by the consumers? I think there will be no point in consumers using the interfaces, as they would generally only use the api object. On the other hand, this would have little priority to me because as @toddbaert said, these represent the OpenFeature API and would not be changed in a breaking way by nature besides from a intended breaking version.
I don't feel strongly about this... one possible advantage I guess is we could, in-future, version these separably, right? I'm not sure that's a great idea though.
We have this discussion with basically every SDK :D I also do not have a strong opinion on this, but for this discussion I am always leaning towards having env and in-memory providers in the SDK package. They are the most basic ones we provide. For the multi-provider I am not sure.
[Suggested by @toddbaert] We could consider removing these functions entirely. They return errors directly, which add complexity and is arguably against the spec, which says evaluation methods should never abnormally terminate (returning a non-nil error in Go signals an abnormal termination equivalent to throwing IMO). People actually complained about the ergonomics of these and we implemented the non-error-returning versions in response. The "detailed" evaluation methods also return errors, and we have no "non-error" variant. We should consider our options here to make these consistent and idiomatic.
For a v2 I fully support this. As @toddbaert says, returning errors is not spec conform and these functions became legacy with the new functions.
Out of the list above, only number 8 and potentially number 1 (depending on how/where we introduce generics) will cause a breaking change to providers.
@sahidvelji for 8, it is only because of introducing the error right? Adding context can be done without breaking. For 1, where would we have to break instead of just having a default type?
For example, for those identifiers that are to be renamed, we can create the target type/function and deprecate the old one. Then once v2 is created, all we need to do is delete the deprecated identifiers, making that transition a bit easier on our end.
I fully support deprecating stuff we are going to remove first and give some time to transition while fixing the non-breaking things and the do the V2 with the removal and necessary breaking changes.
Overall I think I am fine with a v2 here if people closer to the users of this SDK think that combined these items rise to the level which merits the associated disruption, or that it will be a minor enough update that it won't really be disruptive.
Same for me, I think this is becoming worth the breaking change.
To summarize, I support V2 and doing all the non-breaking change + deprecations first in a 1.x version.
@sahidvelji is the point of this, that they are not needed by the consumers? I think there will be no point in consumers using the interfaces, as they would generally only use the api object. On the other hand, this would have little priority to me because as @toddbaert said, these represent the OpenFeature API and would not be changed in a breaking way by nature besides from a intended breaking version.
Yes. It's also not good practice to create (and export) such very large interfaces. The bigger the interface, the weaker the abstraction. I don't mind them if they are not exposed to users.
@sahidvelji for 8, it is only because of introducing the error right? Adding context can be done without breaking. For 1, where would we have to break instead of just having a default type?
For 1, I said "potentially" because I haven't had time to think through it yet. Let's say it's TBD for now. Will add another comment here and update the OP when I have those details. For 8, yes.
I added point 11.
If we're generally aligned on the creation of a v2, I would first like to go ahead and deprecate certain identifiers and make all of the non-breaking changes first. As @toddbaert mentioned, I think we could go ahead and create sub-issues. We should label them breaking if they are breaking for ease of tracking.
But again, I would like to emphasize that I think we should NOT create a v2 module until after we have made all possible non-breaking changes first, including any deprecations.
I think we can proceed as described.
If it's alright with you @sahidvelji , I will proceed by basically turning each of these points into a child issue of this one, labeling them appropriately. I will probably add "needs discussion" on a few if the definition-of-done isn't immediately clear and further consensus is needed.
Thanks @toddbaert. Sounds good, please do.
I've converted every point to it's own sub-issue, and labelled them with v2. You can see them all with this query: https://github.com/open-feature/go-sdk/issues?q=is%3Aissue%20state%3Aopen%20label%3Av2
You can also see another label (needs discussion) in cases where, IMO, we need to build some consensus on changes first; please use the issues for such discussion. I don't see anything here as overly controversial, and I think the policy should be "speak up or we'll proceed as outlined", so please object if you have objections!
Should we also replace all of go-logr with slog from the standard library as well?
Should we also replace all of
go-logrwithslogfrom the standard library as well?
Almost certainly.