Ruby Challenge: Feature flagging in Python

Filipe Correia
Runtime Revolution
Published in
5 min readAug 17, 2017

--

I’ve been programming in Python for the last year. I’d rather work in Ruby but there are some features in Python and some of its libraries that are really cool. In this post I’m gonna talk about decorators in general and the @patch decorator in particular and how I’ve used it in some projects to implement feature flagging.

Decorators

Decorators aren’t exclusive to Python, Java has them and there’s a proposal to add them to JS. They don’t exist in Ruby (though that hasn’t stopped Yehuda from implementing them). In Python we can decorate functions or classes, for the purpose of this article I’ll focus just on function decorators.
So what is a function decorator?
It’s a function that decorates another function(duh!). Basically when defining a decorator you can define code to run before and after the decorated function is called, you can use this to change the functions arguments and even its return value.

To use a decorator in Python you just add the decorator prefixed with @ before the method declaration, we can use this, for example, to create an argument logger decorator like so:

Creating an actual decorator is a bit messy in my opinion and I usually have to look it up when I wanna write my own, but there are some pretty useful decorators provided by other libraries which I use all the time.

The @patch decorator

The unittest modules is a testing framework for writing unit tests that is part of the Python core libraries. It has a bunch of assertion methods, a TestCase class that all tests should inherit from (similar to minitest), and a pretty powerful set of mocking utilities, amongst which is the @patch function decorator.

The @patch decorator is used when you want to mock the import of a file in another file. The way it works is you decorate the test method with the @patch decorator and in it you specify the path to mock. So in the scope of that test method the object is mocked. You can use the @patch decorator like this:

In the example the Mainframe class in the iron_man.py file is mocked in the test test__connect_to_mainframe_success. The mocked mainframe class is passed as the first argument of the test method, the mainframe_mock object is an instance of MagicMock which is also part of the unittest module.

You can also just set the value of the object you’re patching by passing it as a second argument to the @patch decorator which we’ll see in a later example.

Feature flags

Feature flags are ways to toggle functionality and behaviour in an app. Wether you want to have a bunch of code that you want to run in production but in a controlled way or only have features that are only available to some users, features flags are one of the ways you can manage that. When using feature flags I find its important that:

1) It’s easy to check if a feature is turned on or off.

2) You can test two code paths, one with the feature turned on and one with the feature turned off.

3) You can clean up dead code easily once the feature flag has been turned on for good.

Feature flags need to be stored somewhere. They can be stored in a database and be tied to a user or user role in an application or it can be as simple as an environmental variable. For the things I want to show you I’m going to use environment variables because it requires the least amount of code to provide a working example. So our feature flagging bogs down to a features.py file where each feature is grabbed from the environment and a class that needs to check the value of the flag just imports it from the features module like this:

Patching feature flags

Now to tie everything together we’re going to use the @patch decorator to set feature flags on unit tests. Lets take this code example:

Testing it like that doesn’t really work because one test needs the feature flag turned on while the other needs it turned off, so with the help of the @patch decorator we can do just that.

Now to address the 3 requirements I raised in the beginning with some good old confirmation bias:

1) It’s easy to check if a feature is turned on or off in the code, its one line to import the feature.

2) You can test two code paths, one with the feature turned on and one with the feature turned off by patching the feature in the method you’re testing.

3) You can clean up dead code easily once the feature flag has been turned on for everyone, just search for the feature name on the code, leave the tests with the feature turned off to make sure they fail and remove everything. You can even use the features.py file as manifest of the features you need to clean in your code base.

I love to write Ruby code and it’s sometimes frustrating to write stuff in Python but in some cases I’ve used some python constructs that don’t exist in Ruby to do some pretty cool stuff. I think its important to dip the toe in as many programming languages as we can to see how problems are solved using the different features each language offers.

Here are links to some of the stuff I mentioned along the article but didn’t want you to click away:

Extra stuff:

Have a simple way of doing feature flags in Ruby without using any gems? Got any other cool stuff in Python that you think Ruby can’t do? Just write about your experience or leave a comment.

At Runtime Revolution I’ve learned different languages and frameworks and have always used that knowledge to try and build easy to read and maintain systems.

--

--