Skip to content

Commit e25cbad

Browse files
committed
Merge pull request iluwatar#367 from mikulucky/master
Feature Toogle PR
2 parents 6caea85 + c7f4311 commit e25cbad

File tree

19 files changed

+848
-0
lines changed

19 files changed

+848
-0
lines changed

feature-toggle/etc/feature-toggle.png

54.1 KB
Loading
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<class-diagram version="1.1.9" icons="true" automaticImage="PNG" always-add-relationships="true" generalizations="true"
3+
realizations="true" associations="true" dependencies="true" nesting-relationships="true" router="FAN">
4+
<interface id="1" language="java" name="com.iluwatar.featuretoggle.pattern.Service" project="feature-toggle"
5+
file="/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/Service.java" binary="false"
6+
corner="BOTTOM_RIGHT">
7+
<position height="-1" width="-1" x="238" y="187"/>
8+
<display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
9+
sort-features="false" accessors="true" visibility="true">
10+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
11+
<operations public="true" package="true" protected="true" private="true" static="true"/>
12+
</display>
13+
</interface>
14+
<class id="2" language="java"
15+
name="com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion" project="feature-toggle"
16+
file="/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java"
17+
binary="false" corner="BOTTOM_RIGHT">
18+
<position height="-1" width="-1" x="241" y="449"/>
19+
<display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
20+
sort-features="false" accessors="true" visibility="true">
21+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
22+
<operations public="true" package="true" protected="true" private="true" static="true"/>
23+
</display>
24+
</class>
25+
<class id="3" language="java" name="com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion"
26+
project="feature-toggle"
27+
file="/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java"
28+
binary="false" corner="BOTTOM_RIGHT">
29+
<position height="149" width="230" x="502" y="119"/>
30+
<display autosize="false" stereotype="true" package="true" initial-value="true" signature="true"
31+
sort-features="false" accessors="true" visibility="true">
32+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
33+
<operations public="true" package="true" protected="true" private="true" static="true"/>
34+
</display>
35+
</class>
36+
<class id="4" language="java" name="com.iluwatar.featuretoggle.user.User" project="feature-toggle"
37+
file="/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java" binary="false" corner="BOTTOM_RIGHT">
38+
<position height="-1" width="-1" x="616" y="453"/>
39+
<display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
40+
sort-features="false" accessors="true" visibility="true">
41+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
42+
<operations public="true" package="true" protected="true" private="true" static="true"/>
43+
</display>
44+
</class>
45+
<class id="5" language="java" name="com.iluwatar.featuretoggle.user.UserGroup" project="feature-toggle"
46+
file="/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java" binary="false"
47+
corner="BOTTOM_RIGHT">
48+
<position height="-1" width="-1" x="956" y="187"/>
49+
<display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
50+
sort-features="false" accessors="true" visibility="true">
51+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
52+
<operations public="true" package="true" protected="true" private="true" static="true"/>
53+
</display>
54+
</class>
55+
<dependency id="6">
56+
<end type="SOURCE" refId="1"/>
57+
<end type="TARGET" refId="4"/>
58+
</dependency>
59+
<dependency id="7">
60+
<end type="SOURCE" refId="3"/>
61+
<end type="TARGET" refId="5"/>
62+
</dependency>
63+
<association id="8">
64+
<bendpoint x="911" y="415"/>
65+
<end type="SOURCE" refId="5" navigable="false">
66+
<attribute id="9" name="freeGroup">
67+
<position height="19" width="63" x="846" y="368"/>
68+
</attribute>
69+
<multiplicity id="10" minimum="0" maximum="2147483647">
70+
<position height="17" width="23" x="707" y="418"/>
71+
</multiplicity>
72+
</end>
73+
<end type="TARGET" refId="4" navigable="true"/>
74+
<display labels="true" multiplicity="true"/>
75+
</association>
76+
<realization id="11">
77+
<end type="SOURCE" refId="2"/>
78+
<end type="TARGET" refId="1"/>
79+
</realization>
80+
<dependency id="12">
81+
<end type="SOURCE" refId="2"/>
82+
<end type="TARGET" refId="4"/>
83+
</dependency>
84+
<dependency id="13">
85+
<end type="SOURCE" refId="3"/>
86+
<end type="TARGET" refId="4"/>
87+
</dependency>
88+
<association id="14">
89+
<bendpoint x="953" y="459"/>
90+
<end type="SOURCE" refId="5" navigable="false">
91+
<attribute id="15" name="paidGroup">
92+
<position height="19" width="66" x="963" y="419"/>
93+
</attribute>
94+
<multiplicity id="16" minimum="0" maximum="2147483647">
95+
<position height="17" width="23" x="711" y="463"/>
96+
</multiplicity>
97+
</end>
98+
<end type="TARGET" refId="4" navigable="true"/>
99+
<display labels="true" multiplicity="true"/>
100+
</association>
101+
<realization id="17">
102+
<end type="SOURCE" refId="3"/>
103+
<end type="TARGET" refId="1"/>
104+
</realization>
105+
<classifier-display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
106+
sort-features="false" accessors="true" visibility="true">
107+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
108+
<operations public="true" package="true" protected="true" private="true" static="true"/>
109+
</classifier-display>
110+
<association-display labels="true" multiplicity="true"/>
111+
</class-diagram>

feature-toggle/index.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
layout: pattern
3+
title: Feature Toggle
4+
folder: feature-toggle
5+
permalink: /patterns/feature-toggle/
6+
categories: Behavioral
7+
tags:
8+
- Java
9+
- Difficulty-Beginner
10+
---
11+
12+
## Also known as
13+
Feature Flag
14+
15+
## Intent
16+
Used to switch code execution paths based on properties or groupings. Allowing new features to be released, tested
17+
and rolled out. Allowing switching back to the older feature quickly if needed. It should be noted that this pattern,
18+
can easily introduce code complexity. There is also cause for concern that the old feature that the toggle is eventually
19+
going to phase out is never removed, causing redundant code smells and increased maintainability.
20+
21+
![alt text](./etc/feature-toggle.png "Feature Toggle")
22+
23+
## Applicability
24+
Use the Feature Toogle pattern when
25+
26+
* Giving different features to different users.
27+
* Rolling out a new feature incrementally.
28+
* Switching between development and production environments.
29+
30+
## Credits
31+
32+
* [Martin Fowler 29 October 2010 (2010-10-29).](http://martinfowler.com/bliki/FeatureToggle.html)

feature-toggle/pom.xml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
The MIT License
5+
Copyright (c) 2014 Ilkka Seppälä
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
25+
-->
26+
27+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
28+
xmlns="http://maven.apache.org/POM/4.0.0"
29+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
30+
<parent>
31+
<artifactId>java-design-patterns</artifactId>
32+
<groupId>com.iluwatar</groupId>
33+
<version>1.10.0-SNAPSHOT</version>
34+
</parent>
35+
<modelVersion>4.0.0</modelVersion>
36+
37+
<artifactId>feature-toggle</artifactId>
38+
39+
40+
<dependencies>
41+
<dependency>
42+
<groupId>junit</groupId>
43+
<artifactId>junit</artifactId>
44+
<scope>test</scope>
45+
</dependency>
46+
47+
</dependencies>
48+
</project>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
* <p>
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
* <p>
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
* <p>
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.featuretoggle;
25+
26+
import com.iluwatar.featuretoggle.pattern.Service;
27+
import com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion;
28+
import com.iluwatar.featuretoggle.user.User;
29+
import com.iluwatar.featuretoggle.user.UserGroup;
30+
31+
import java.util.Properties;
32+
33+
/**
34+
* The Feature Toggle pattern allows for complete code executions to be turned on or off with ease. This allows features
35+
* to be controlled by either dynamic methods just as {@link User} information or by {@link Properties}. In the App
36+
* below there are two examples. Firstly the {@link Properties} version of the feature toggle, where the enhanced
37+
* version of the welcome message which is personalised is turned either on or off at instance creation. This method
38+
* is not as dynamic as the {@link User} driven version where the feature of the personalised welcome message is
39+
* dependant on the {@link UserGroup} the {@link User} is in. So if the user is a memeber of the
40+
* {@link UserGroup#isPaid(User)} then they get an ehanced version of the welcome message.
41+
*
42+
* Note that this pattern can easily introduce code complexity, and if not kept in check can result in redundant
43+
* unmaintained code within the codebase.
44+
*
45+
*/
46+
public class App {
47+
48+
/**
49+
* Block 1 shows the {@link PropertiesFeatureToggleVersion} being run with {@link Properties} setting the feature
50+
* toggle to enabled.
51+
*
52+
* Block 2 shows the {@link PropertiesFeatureToggleVersion} being run with {@link Properties} setting the feature
53+
* toggle to disabled. Notice the difference with the printed welcome message the username is not included.
54+
*
55+
* Block 3 shows the {@link com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion} being
56+
* set up with two users on who is on the free level, while the other is on the paid level. When the
57+
* {@link Service#getWelcomeMessage(User)} is called with the paid {@link User} note that the welcome message
58+
* contains their username, while the same service call with the free tier user is more generic. No username is
59+
* printed.
60+
*
61+
* @see User
62+
* @see UserGroup
63+
* @see Service
64+
* @see PropertiesFeatureToggleVersion
65+
* @see com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion;
66+
*/
67+
public static void main(String[] args) {
68+
69+
final Properties properties = new Properties();
70+
properties.put("enhancedWelcome", true);
71+
Service service = new PropertiesFeatureToggleVersion(properties);
72+
final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code"));
73+
System.out.println(welcomeMessage);
74+
75+
// ---------------------------------------------
76+
77+
final Properties turnedOff = new Properties();
78+
turnedOff.put("enhancedWelcome", false);
79+
Service turnedOffService = new PropertiesFeatureToggleVersion(turnedOff);
80+
final String welcomeMessageturnedOff = turnedOffService.getWelcomeMessage(new User("Jamie No Code"));
81+
System.out.println(welcomeMessageturnedOff);
82+
83+
// --------------------------------------------
84+
85+
final User paidUser = new User("Jamie Coder");
86+
final User freeUser = new User("Alan Defect");
87+
88+
UserGroup.addUserToPaidGroup(paidUser);
89+
UserGroup.addUserToFreeGroup(freeUser);
90+
91+
final String welcomeMessagePaidUser = service.getWelcomeMessage(paidUser);
92+
final String welcomeMessageFreeUser = service.getWelcomeMessage(freeUser);
93+
System.out.println(welcomeMessageFreeUser);
94+
System.out.println(welcomeMessagePaidUser);
95+
}
96+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
* <p>
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
* <p>
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
* <p>
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.featuretoggle.pattern;
24+
25+
import com.iluwatar.featuretoggle.user.User;
26+
27+
/**
28+
* Simple interfaces to allow the calling of the method to generate the welcome message for a given user. While there is
29+
* a helper method to gather the the status of the feature toggle. In some cases there is no need for the
30+
* {@link Service#isEnhanced()} in {@link com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion}
31+
* where the toggle is determined by the actual {@link User}.
32+
*
33+
* @see com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion
34+
* @see com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion
35+
* @see User
36+
*/
37+
public interface Service {
38+
39+
/**
40+
* Generates a welcome message for the passed user.
41+
*
42+
* @param user the {@link User} to be used if the message is to be personalised.
43+
* @return Generated {@link String} welcome message
44+
*/
45+
String getWelcomeMessage(User user);
46+
47+
/**
48+
* Returns if the welcome message to be displayed will be the enhanced version.
49+
*
50+
* @return Boolean {@value true} if enhanced.
51+
*/
52+
boolean isEnhanced();
53+
54+
}

0 commit comments

Comments
 (0)