How does this work in a developers local environment? Does it hook into the same central service or do you need re-define the gate in all environments?
At Instagram we have split dev and prod enviroments; gates are shared between dev-servers, but split from production.
For testing, we have context managers that let you do "with temporary_gate('gate_name', value)", so there's not much boilerplate in overriding/testing your code within a gate constraint.
I do agree with your point 1,2,3, rule-based is better in some cases, but it's not as expressive, sometimes you have to express the logic in a non-straightforward way to satisfy your need, when the logic get complicated. We're trying to make the system flexible from the backend, and improve the usability at the UX level. For example, the constants inside the language will go to a separate section in the UI and will have various components of tuning them.
If the DSL code is organized well, it's going to look as clean as the rule based one.
I'm not clear from the post, is this used only to gate features in servers or is this used to gate features in the mobile clients as well? If it's used in the mobile clients, how is that done (in particular, checking looks to be synchronous, but would obviously need to be async to work)
This is primarily a server-gating feature. For the mobile clients, they periodically sync their experiment flags state using a call to the backend (eg at app start), which is handled using a related, but separate, system to Gate Logic.
what advice would you give to someone who would be looking to implement this in a less dynamic language such as C# or Java? In your opinion is this only successful due to the dynamic and special language features of Python?
That's a very good question. It depends on your usecase. You can certainly do it in a more straightforward way, just design the language and write an "interpreter" to execute the language. But if performance matters, you'll have to generate native VM bytecode instead of the bytecode interprets the language.
I believe Java/C# both have this kind of tool to hook into the compiler and generate bytecode, either official or 3rd-party. For Java it might be asm, don't know a lot about C#, but since Microsoft has open-sourced their compiler, I think that's possible.
A lot of dynamic languages do provide native interpreter interaction, like Python AST, I'd say it makes things a lot easier, but totally doable in other "not-so-dynamic" language.
Might be hard with total compiled languages like C++ though, otherwise we have to distribute gcc/clang to the production machine :-p