# Don’t Use Boolean Flags in Python, Use Policies Instead

## Метаданные

- **Канал:** ArjanCodes
- **YouTube:** https://www.youtube.com/watch?v=wYeDGkdMi3g
- **Дата:** 24.04.2026
- **Длительность:** 15:09
- **Просмотры:** 113,367
- **Источник:** https://ekstraktznaniy.ru/video/49398

## Описание

🧱 Build software that lasts. Join the Software Design Mastery waiting list → https://arjan.codes/mastery.

In this video, I show how to replace growing conditional logic with the Policy Pattern. Instead of one big function, you split rules into small, composable pieces and combine them into a flexible pipeline. The result is code that’s easier to extend, test, and control even with feature flags or configuration.

🔥 GitHub Repository: https://git.arjan.codes/2026/policy.

🎓 ArjanCodes Courses: https://www.arjancodes.com/courses.

💬 Join my Discord server: https://discord.arjan.codes.

⌨️ Keyboard I’m using: https://amzn.to/49YM97v.

🔖 Chapters:
0:00 Intro
2:11 The Problem
2:34 The Policy Pattern
3:05 OOP Version (Quick Overview)
5:50 Strategy vs Policy
6:51 Functional Style (Pythonic Version)
10:56 Policy Registry + Settings
13:37 Why This Is Powerful
14:07 Trade-offs
14:22 Final Thoughts

#arjancodes #softwaredesign #python

## Транскрипт

### Intro []

Here's a function that I see all the time in real Python code. There are few flags, some if statements. It actually looks fine until you add one rule and you add another one and suddenly this function is starting to do everything. Now, the problem is that this code doesn't work. It does, but it doesn't really scale. In this video, I'm going to show you a better way to structure this using the policy pattern. You may not have heard about that one. But a nice bonus with this pattern is that there's a really clean way to turn pieces of logic like in this function on or off without adding more conditionals. Now, if you ever looked at your own code and thought, "This is a huge mess and I don't see a structured way to fix it. " That is why I'm creating the software design mastery program. This is not just another course with a bunch of videos. I go much deeper into how to actually design systems like this in a clean, scalable way. If you want to be the first to hear when it launches, join at aronaldcodes/mastery. The link is also in the video description. Now, in this particular function, we have a user and a request object. And depending on some rules, then either a permission error is raised or an audit log is being written to and in the end, what this function actually does is grant access to this particular user. Now, there's also a simple main function where I create a user and request. This is purely to demonstrate how this is supposed to work. Then I process the request and I print the result, which is actually the modified request that also has the audit. Now, if you look at this request object, this is in another file that I'm not going to modify in today's video, but there's a few classes here, data classes that contain some information like the user which has a name, roles, a couple of other things, and a request object. Now, this example, I'm just using objects here, but you may want to read this from a database in a real production system. When I run the original messy version of the code, then this is what we get. We get an request object. As you can see, there is an audit log here and access granted is set to true. In this

### The Problem [2:11]

particular example, process request is actually turning into a big function that does all of the checks. And like I said, the problem here is that once you add more rules and there are going to be more rules always, they get added to the same place. And that means you're running into all sorts of problems. It's hard to extend, hard to test, it's hard to reuse parts, etc. And this is how simple code slowly becomes completely unmanageable. Now, instead of one big

### The Policy Pattern [2:34]

function, you can actually split these rules into so-called policies. And a policy is basically one rule, one responsibility. For example, we could have an active user policy or an multi-factor authentication policy or a role policy or an auditing policy. Essentially, what you're doing then is that you shift from having all of these conditions that you need to check to what rules actually apply here. Now, I

### OOP Version (Quick Overview) [3:05]

have another version of this code that is set up exactly in this way. And this is using object-oriented programming. I know we don't all like that in Python, but I wanted to start here to stay more closely to how you may be used to seeing design patterns like this. So, the way this works is that we have a certain policy class. This is a base class that has a simple method called apply. It gets a user and it gets a request and that applies a certain policy. And I'm using a protocol class here and then later on, I define classes. If you're using an abstract base class, these would be subclasses, but here with protocols, it's not necessary. Where actually we provide implementations for all of these different rules. So, there is the active user policy. Now, in the messy version before, we had this code directly in our process request function. Whereas here, this is in a class and we apply the policy. And we can have multiple of these. So, there is a multi-factor authentication policy. There is a role policy. There is an audit policy. And even the logic for granting access, which is here in the function, we can also turn that into a policy if we want to. We don't have to, but we could. So, there is a grant access policy. And then, what you can do is compose these. So, you would have a list of policies that is part of another class, composite policy, that also has an apply method. Gets a user and a request. And for each of the policy in the list, it's going to apply that particular policy. And then, what you can do, instead of having this process policy function with all this logic, you could create the composite policy as a list of policies and then simply apply that and then print the result. And when I run this, we get exactly the same result. Except now, the code is set up very differently. So, we have these different classes where all the rules are located and we don't have all of this in one single place like we had in this first version of the code. Now, the advantage here is that rules are explicit. They're easy to test individually because I can just create instances of these classes and they're also easy to reuse because I can simply access those objects in various parts of my code. Most importantly, there is not a giant block of conditions. Now, of course, we also lose things here because we have a bunch of classes now that we have to write. There's more lines of code in this rewrite. We now have 82 lines, whereas in the messy version, we have only 45. So, we have double the amount of code for the same behavior. So, it seems like we're kind of overcomplicating things here. So, as a

### Strategy vs Policy [5:50]

next step, I'll rewrite this to make this again a bit more Pythonic. I might wonder, "Hey, actually, doesn't this look a lot like the strategy pattern? Isn't that kind of the same thing? " Actually, if you look on Wikipedia at the strategy pattern page, you see that it kind of treats them as the same thing. Policy is seen as a sort of synonym as strategy. Now, structurally, that is kind of true in a sense that we encode behavior in a method in a class and then supply an object and then call it from there. But in practice, to me, they are actually quite a bit different. With strategy, it's more about picking a particular algorithm like a sorting algorithm. That's like the classic example. Whereas for policies, it's more about combining rules and to me, that difference matters even though you use the same programming language features for both of these patterns. But to me, the main difference is that with strategy, it's more about choosing one particular algorithm. Whereas with policies, it's more about how you compose these things. Now, of course

### Functional Style (Pythonic Version) [6:51]

talking about composition, we might think, "Well, you know, do we really need all these classes? " In Python, we can actually simplify this a lot further by using functions instead of classes. So, the way you would do that is that, well, first, we're not going to need this protocol because we will use functions instead. And then, actually, these things become functions instead of methods. So, this is let's say active user. We don't need to pass self. Remove the class and I can do the same thing for the other policy classes. So, we have role required, grant access, and audit. And note that I'm using the replace function here to modify the actual request object. This is something that's from the data classes module. It's very useful, actually. So, now that we have these functions, instead of having a composite policy class, we can actually use function composition. But before we do that, it will actually be helpful if each of these policies actually also returns the request so we can basically pass this request object through the different policy functions. So, I'm going to modify these functions here to actually return a request object. So, this doesn't really change the behavior of the function. It just makes it easier to compose them later on. And as you can see, I already did this work for the functions I pasted in a minute ago. So, now we have these functions that each take user and request and return a potentially modified request. And then, we can apply these as a pipeline. Now, in order to do that, we can simply create a function that does it like this with a for loop, but we can also use function composition. So, in order to do that, from the functools module, I'm going to import the reduce function. Which will help us do that very quickly. And then, I'm going to create a function called apply policies. And this will get a user. It will have a request. And it's going to get a list of policy functions. So, let's write that as a policy function type, which we can define later on. So, for now, I'll just write this. I'll fill that in later. But let's define a type here. Policy function. And this is going to be a callable, which we'll need to import from typing. And this is a function that gets a user, request, and it will return a request. And then, for applying these policies, let's actually make this truly composable. I also letting this return a request. So, this is going to return reduce. And this will get a lambda function with the current value and the new policy. And then, this will call the policy on the user and the current policy. And we feed it the list of policies and the request. And then now, instead of having this composite, we can actually create a list of policies here. And there, we simply define them by passing the functions. And then, we apply the policies to the user request, and we supply the list of policies, like so. And then, let's store that as a result. So now, when I run this, as you can see, we get exactly the same result. So now, by doing this, we did again reduce the code that we used as less boilerplate than with the classes, but this is also very composable. Because now, if we want more rules, we can simply add them to our list of policies right here, and we can simply define functions for that, test those functions, maybe put them in different modules, gives us a lot of flexibility. Now, the really useful part

### Policy Registry + Settings [10:56]

is, if we go back to the initial version of the code, we had all these conditions here. So in the current version, we don't have those conditions anymore. And because the policies are now in the list, we can actually write code that modifies these lists. We can make it fully data-driven. For example, you could keep a registry of policy names and map them to functions, and then load those enabled policies from a settings object. And then, you can build the pipeline from that list. Here's what that could look like. So I have a dictionary here, policy registry, that maps these names to function names. You could even make this fancy with decorators that auto-register these functions. I did that in other videos as well, if you want to learn how to do that. Uh but then, basically, the next step could be that you define a settings object. And this is using Pydantic settings. So, this is a base settings subclass. I define what the enabled policies are. Default, these are going to be these ones. Um and then, I read these from a dot env file. Now, the dot env file is very simple. It just contains this environment variable with the list of active policies. You could decide to read this from an environment variable that's defined in your Docker container, for example, or even better, that is passed along in your cloud environment. And then, this determines which policies are active. And then, it's really easy to use this. I created a simple get policies function here that gets settings object, and that returns policies for each of these enabled policies from the settings. And then, in my main file, I get these policies, and then I call the apply policies function, like I did before. And now, if I run this, you see that we get a list of enabled policies that I'm just printing for logging, and then we get the request as a result. And now, I can change things by simply enabling or disabling policies in the dot env file. So, for example, if I remove granting access, so here you can see access granted is true, but now, if I run this version of the code, you see that I no longer get access, because we disabled that policy from a setting. So, this is, in my opinion, really neat solution. It's a bit more complex than the original version of the code, but it gives us way more control. There's no explosion of if statements. Uh we have configuration that controls the actual behavior, and this also gives us really easy feature flag mechanism that we can control from outside of the code. And adding a policy now becomes very simple. We write a function, we register it, and we add a name to config, and that's basically it. So, to

### Why This Is Powerful [13:37]

me, this is very powerful. These flags, they don't leak into your logic. The policies, they clean and focused. Configuration controls how things are composed. The order is explicit and configurable. And this is exactly what you want in real production system. Basically, a lot of flexibility without the chaos. Now, if you enjoy these kinds of practical design pattern videos that actually clean up real Python code, give this video a like. Consider subscribing for more content like this. Now, there

### Trade-offs [14:07]

is a trade-off here, of course. We had to write more code in order to achieve this. There were more functions or classes. We need slightly more upfront thinking on order for this to work. Uh on the other hand, this is much easier to extend, to test, and to maintain. So

### Final Thoughts [14:22]

in the end, it all depends on what you need. You wouldn't use this for a simple throwaway script, but for a bigger production system where you want a lot of control over the logic, this might be a really nice way to do it. And in particular, if you're doing it in Python, I think combining this type of pattern with the more functional style, a simple registry, and a settings object, it gives you a very flexible design. But, I'd like to hear what you think. Where in your code base are you still using these big conditional functions, like I showed you at the start? Do you think those could be replaced by a pipeline of policies? Let me know in the comments. Now, if you want to explore more software design patterns, check out my design patterns playlist right here. Thanks for watching, and see you next time.
