Dirk Nachbar just published a useful little WebLogic Scripting Tool (WLST) script to start or stop multiple WebLogic Managed Servers. A simple refactoring extends his effort to make the script a bit more compact and arguably easier to maintain. This refactoring turns up in many other scripts, far removed from WebLogic or even Python.
Nachbar sets the context: “[t]he classical approach to startup or shutdown … multiple Managed Servers …” is a bit fragile. It’s too easy to think you have acted on a list of managed servers, when in fact a fault in one affects the action of the “classical approach” on other servers. Nachbar corrects this: his script has the sense to complete correctly, even if it encounters one or more managed servers in an unexpected state.
He implements his script with separate loops for the ‘start’ and ‘stop’ cases. It’s easy, though, to take his scripting one step further, and transpose the order of operation so that the loop is in control. He wrote
... # Start Block if getcommand == 'start': # Loop over the splitted Server List string for s in serverlistSplit: # Is a ServerRuntime MBean existing for current Managed Server? # If yes, the current Managed Server is already running and we dont need to do anything bean = getMBean('ServerRuntimes/' + s) if bean: print 'Server ' + s + ' is ' + bean.getState() else: start(s, 'Server', block='false') print 'Started Server ' + s # Stop Block if getcommand == 'stop': # Loop over the splitted Server List string for s in serverlistSplit: # Is a ServerRuntime MBean existing for current Managed Server? # If no, the current Managed Server is already down and we dont need to do anything bean = getMBean('ServerRuntimes/' + s) if bean: shutdown(s, 'Server') print 'Stopped Server ' + s else: print 'Server ' + s + ' is not running'
Contrast this with
... def startAction(bean, s): # If yes, the current Managed Server is already running and we need do nothing more. if bean: print 'Server ' + s + ' is ' + bean.getState() else: start(s, 'Server', block='false') print 'Started Server ' + s def stopAction(bean, s): # If no, the current Managed Server is already down and we need do nothing more. if bean: shutdown(s, 'Server') print 'Stopped Server ' + s else: print 'Server ' + s + ' is not running' action['start'] = startAction action['stop'] = stopAction # Loop over the splitted Server List string for s in serverlistSplit: # Does the current Managed Server have a corresponding # ServerRuntime MBean? action[getcommand](getMBean('ServerRuntimes/' + s), s)
Consider the details of these two. First, I want to emphasize that for me to offer an alternative is not a criticism of Nachbar. His script has at least two excellent qualities I can’t best: it works as advertised; and it considerably improves on what was available without it. The coding I offer has only the same functionality as his. Many readers will prefer his coding.
Preference for small structures
I particularly favor “shallow” implementations, though–ones with few levels of nested branching–and like to style source more in the manner of the second example above. A starting point in comparing the two, for me, is to note that Nachbar’s main segment has four conditionals (two comparisons of
getcommand, and two of
bean), along with two loops. Mine has two conditionals, and one loop–but also two function definitions.
Even more than that, I like the “enhancement path” of my implementation. To add a “restart”, “pause”, or other verb alongside “start” and “stop” with Nachbar’s scheme generally involves two more conditionals, and one loop; my implementation requires one conditional, within one new function definition. That sort of minimization of branching appeals to me.
For those even more inclined to “flatten” than am I, it’s also possible to eliminate the named functions
stopAction. Python supports anonymous functions, and reliance on them provides another alternative coding.
Much of the difference between these alternative styles comes down to a matter of taste; reasonable coders can recognize the different possibilities and still disagree about which are most congenial or otherwise best. One of the aspects of Nachbar’s example that first caught my attention, though, is that the refactorings it admits depend only weakly on language. Whether you do your administrative scripting in Jython, as WLST requires, or Powershell or bash or another language, similar techniques are available to you. You can invert branch nesting, (effectively) assign functions to variables, dereference associative variables (dictionaries, hashes, variable variables), and otherwise refactor source to style it the way most convenient to you.
Nachbar’s posting emphasizes automation, and better exception-handling. In this case, the exception to be handled is stopping an already-stopped Managed Server, or otherwise trying to take an incompatible action. Automation and exception-handling are, let’s say, 95% of the value of a script. If my “shallower” coding helps make it easier to maintain such a script, in the amount of 5% of its value, I’m well-satisfied.