Feature switch framework proposal explained
I’ve written a blog last week about an idea for a feature switch framework that I want to open source and get feedback on.
In this blog I’ll try to explain my initial thoughts and are hoping for your feedback.
So briefly the intention is to build a feature switch framework that would enable an organisation to quickly turn off new code changes that has been brought in via transports if proven buggy. This buys the organisation time to provide a proper fix. I can vouch for this where i’m at currently as there is a very lengthy governance process.
The other part of it would be to enable new development to be rolled out gradually instead of always a big bang release when the code hits production. This enables you to run beta program and early releases to get the feedback from your end users earlier than otherwise as they can get their hands dirty.
So my concept so far relies on a few different factors:
- Enable global switches to quickly turn on or off an enhancement
- Enable beta testing capabilities to limit the risk of go lives and also to get early feedback on changes
- Be able to control the beta testing either via a custom authorization object or a user table
- Enable the feature switch to quickly append to the application log if desired
- Transaction where you can maintain the switches with a tree like menu structure for the various maintenance steps with documentation
So when configured, you would encapsulate your changes with an IF/ELSE statement to either run the new or old code depending on the feature switch.
If the switch is turned on, then return true and run the changes, otherwise run the old stuff.
Now to something slightly more complex.
If you want the code change only to be applicable to certain calling classes, then you would have a enable switch method to locally enable the switch for your code and then disable it again afterwards. The zfeature table would be buffered in the object class to only have the feature enabled locally for that particular session.
This would prove helpful for example when messing around with enhancements or modifications to SAP standard code.
If you want to use the beta features, you simply add the name of your feature to a custom auth object and assign it to a user, then that particular user would have your new changes, everyone else wouldn’t. When the beta is over and you want to roll out to the rest of the organisation, then you delete or set an end date to the auth object in the role and the feature is now globally enabled.
I’ll go though the code I have so far.
1 METHOD check_switch. 2 DATA: lt_values TYPE TABLE OF us335. 3 4 SELECT SINGLE * FROM zfeature INTO @DATA(ls_feature) 5 WHERE feature = @iv_feature. 6 7 IF sy-subrc = 4. 8 RAISE EXCEPTION TYPE zcx_feature_switch. 9 10 ELSEIF ls_feature-enabled = abap_false and ls_feature-class_enabled = abap_false. "Feature switch is turned off 11 ev_enabled = abap_false. 12 RETURN. 13 ENDIF. 14 15 * Now check if the user has the assigned auth object. 16 SELECT SINGLE usr~AGR_NAME 17 INTO @DATA(lv_agr) 18 FROM AGR_USERS AS USR 19 INNER JOIN AGR_1251 AS VAL 20 ON usr~agr_name = val~agr_name 21 WHERE UNAME = @sy-uname 22 AND DELETED = '' 23 AND val~low = @iv_feature 24 AND from_dat <= @sy-datum 25 AND to_dat >= @sy-datum. 26 27 28 IF sy-subrc = 4. 29 * Check if there are any user whos got the auth object 30 SELECT SINGLE AGR_NAME INTO lv_agr FROM agr_1251 31 WHERE low = iv_feature AND deleted = ''. 32 IF sy-subrc = 0. " Auth value is still active in a role. 33 ev_enabled = abap_false. 34 RETURN. 35 ELSE. 36 ev_enabled = abap_true. 37 RETURN. 38 ENDIF. 39 ELSE. " The values are present on the user 40 ev_enabled = abap_true. 41 RETURN. 42 ENDIF. 43 ENDMETHOD.
First we check if the feature switch is present in the table, if not raise an exception. If it is check if it’s been disabled and return.
If it’s enabled then we check if the user has the auth object with the feature assigned to his user. If not, then check if anyone else has it, if that proves true, then we have enabled the beta capabilities.
If not then the feature is globally available.
The table is fairly simple so far.
The class enabled is to enable the code changes for certain calling classes instead of globally.
This is basically what I have so far, but here are some further thoughts on where I think it could go, please comment on these as I’m very interesting in hearing your thoughts.
- Instead of using a class enabled switch, should we implement another table to enable it for a certain call stack?
- My thoughts are that this could become very cumbersome to maintain
- Add a user table to be able to roll out the features to users without the use of auth objects and then a global switch to decide how to use the beta features via auth object or the user table.
- Add convenience methods to write stuff to the application log and set a flag in the table to enable or disable this.
- Transaction to easily maintain the configuration of the framework with available documentation
- Would include a program to maintain the feature switch table in prod
- Setting up a new feature switch and step by step process maybe including code samples?
- Maintain users in the users table, would be handy if you could add in an org unit or positions as well to add the users to the table, also to remove users easily
- A where used program similar to SUIM for everything with the user master
If you want, you can clone the local package via AbapGit and run it on your system. I’ve added some unit testing based on the following switches
- SWITCH1 – Is globally enabled
- SWITCH2 – Is globally disabled
- SWITCH3 – Is enabled for another user, but not me
- SWITCH4 – Is enabled for my user
- SWITCH5 – Is class enabled for my user
- SWITCH6 – Is class enabled, but not for my user
- SWITCH999 – Doesn’t exist, so throws an exception
I’d appreciate any help and comments.
One criticsm of the concept is that source code will end up being quite convoluted with all these IF/ELSE statements, I think the easiest way to maintain that would be to write new methods for the changes to create isolated code, this would also enable you to do Abap Unit testing on your Island Of Happiness as explained in this OpenSAP course
Hey Jakob Marius Kjær !
I like the idea of switching features on and off.
I have the following doubts:
I accept that a central switch/activation-check framework is useful. I have already used many. They check for a KEY and optional additional PARAM (e.g. organizational units). The feature can be centrally activated/deactivated at system/client/org.unit level.
However, note that depending on the feature you might not save as much time as you think in a lengthy governance process. I see the challenge in building a useful maintenance concept for the activation. Activating/Deactivating a feature is conceptionally the same as SAP customizing. You might have to transport the table content and re-test even when you are only deactivating. Or else how do you make sure the system state with the feature deactivated is always tested/stable? This could be a challenge.
This is also why I do not understand (yet) what you will gain from your next proposal, a central framework for controlling behavior at the level of class usage. It is so powerful that is should treated as development. If done right, I guess you end up creating a lightweigth BAdI or BRF+ framework.
In my view, checking if a feature is active is orthogonal to user-dependent authorization checks. I think each feature implementation should be responsible for its own authority checks. How should a central switch/activation/feature framework (what do you want to call it today?) know how to combine authorization checks for multiple features without becoming an authorization framework?
my 2 cents