Comments (13)
Hey, hi,
I think you're right, AFAIR there isn't really a reason to force group names to be atoms. I could lift the restriction, but that's a breaking change and I need to think a bit about an upgrade path.
In the meantime, to get you unblocked, I'd suggest to use actor gates to simulate dynamic groups.
For example:
defmodule User do
defstruct [:id, :email]
end
defmodule UserBucket do
defstruct [:user]
end
defimpl FunWithFlags.Actor, for: UserBucket do
def id(bucket) do
"users_bucket:" <> bucket_id(bucket.user)
end
def bucket_id(user) do
rem(user.id, 10) |> to_string
end
end
user = %User{id: 42, email: "[email protected]"}
FunWithFlags.enable :my_feature, for_actor: %UserBucket{user: user}
if FunWithFlags.enabled?(:my_feature, for: %UserBucket{user: user}) do
# ... feature-flagged stuff...
end
iex> FunWithFlags.all_flags
{:ok,
[%FunWithFlags.Flag{gates: [%FunWithFlags.Gate{enabled: true,
for: "users_bucket:2", type: :actor}], name: :my_feature}]}
from fun_with_flags.
I came up with the following solution:
Oh, yes, that would work too. As long as you don't end up dynamically creating un unchecked number of atoms, you should be fine (as you said, the VM wouldn't like it because atoms are GC'd).
The main concern about lifting the restriction is that the keys are converted to/from strings when they are inserted in Redis, so if the restriction is lifted there will be no way to know if a key was an atom or string, right?
Well, both the Redis and Ecto adapters will ultimately store the group name as a binary (redis, ecto) and then deserialize it as an atom. Off the top of my head the library could just always convert group names to binaries, including the user-provided ones (so that calls to the public functions wouldn't need to be changed). In that case, there wouldn't really be any need to distinguish between originally atom or binary group names.
from fun_with_flags.
Well, both the Redis and Ecto adapters will ultimately store the group name as a binary (redis, ecto) and then deserialize it as an atom. Off the top of my head the library could just always convert group names to binaries, including the user-provided ones (so that calls to the public functions wouldn't need to be changed). In that case, there wouldn't really be any need to distinguish between originally atom or binary group names.
Treating all group names as binaries implies that everything that implements the String.Chars
protocol could be used as group name. That's awesome! The end user will not feel the difference, as he/she could continue using atom names, but it will be way safer, as no string -> atom conversion would be performed.
BTW, thanks for giving FunWithFlags a try :-)
I hope it's working well.
It's working pretty well so far, we just completed setting up the web UI with some basic auth, pretty awesome lib ^^ Thank you for taking the time and effort needed to create it 😄
from fun_with_flags.
Hi @costaraphael, that PR 👆 adds support for binaries as group names.
from fun_with_flags.
Of course, you'd enable users_bucket:2
in the web GUI instead of using a user directly. That was just a quick proof of concept.
from fun_with_flags.
I came up with the following solution:
defimpl FunWithFlags.Group, for: MyApp.User do
# Atom based groups go here
def in?(user, group) when is_atom(group) do
in?(user, to_string(group))
end
def in?(user, "users_bucket:" <> bucket) do
# bucket checking logic
end
# Other string based groups go here
end
Then I just enable the buckets via: FunWithFlags.enable(:some_flag, for_group: :"users_bucket:2")
.
The main concern about lifting the restriction is that the keys are converted to/from strings when they are inserted in Redis, so if the restriction is lifted there will be no way to know if a key was an atom or string, right?
from fun_with_flags.
BTW, thanks for giving FunWithFlags a try :-)
I hope it's working well.
from fun_with_flags.
implies that everything that implements the String.Chars protocol could be used as group name.
I wouldn't recommend going that far, because group names still need to be displayed in the web GUI. I guess that it would be like you say as a side effect of supporting binaries (if coded in a certain way), but I wouldn't officially support it.
from fun_with_flags.
Thanks a lot man! This will increase a lot the safety of the lib.
Also dynamic group names allow for some crazy (but useful) stuff. What do you think of adding some examples of this to the README? I could write them and send a PR next week, if you are okay with it ^^
from fun_with_flags.
Sure, go for it, thanks!
Maybe the Readme is a bit long already, and was thinking of moving some stuff to the wiki.
What if you add to the readme a link to the wiki, and add your examples to the wiki?
from fun_with_flags.
Sorry, gave it another thought and it would actually be easier to have it in the readme for now. I can sort out the wiki later. 👍
from fun_with_flags.
Or, it could be a page in the hexdocs, like the new phoenix documentation. What do you think?
from fun_with_flags.
The readme is currently included in the hexeocs, so it would end up there. As I said, I've been planning to move the examples somewhere else, and the hexeocs are def a good choice.
from fun_with_flags.
Related Issues (20)
- (UndefinedFunctionError) function Ecto.Query.from/2 is undefined or private HOT 1
- Can't change config without doing a `mix deps.clean fun_with_flags`. HOT 3
- Changing `ecto_table_name` config requires recompile HOT 4
- Setting cache `enabled: false` crashes the app HOT 1
- [Question] Ensuring feature flags are in sync across dev environments HOT 3
- Proposed Postgrex Changes HOT 6
- The module `FunWithFlags.Supervisor` was given as a child to a supervisor but it does not exist HOT 11
- Support redis sentinel HOT 1
- Switch on ecto integration only if Ecto.Adapters.SQL exists HOT 5
- Warnings when FWF is used with ecto HOT 2
- Don't require compile-time configuration HOT 1
- Use case: flag <-> group relationship HOT 5
- mix release issue using Elixir 1.15.0 HOT 2
- Next release and Elixir 1.15 support HOT 2
- `disable/2` returns {:ok, true} HOT 1
- Suggest disabling cache for tests HOT 2
- low priority feature req - automatically remove stale flags HOT 1
- Feature request: Add timestamp columns HOT 1
- Asymmetry between options accepted by `enable`/`disable` compared to `enabled?/2` HOT 5
- Avoid Thundering Herd on Rollout of new Release HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fun_with_flags.