Showing posts with label workflow. Show all posts
Showing posts with label workflow. Show all posts

Tuesday, May 15, 2012

Flexible Business Policies

With any software system, there are business rules. Rules dictate what a user can and cannot do. The order in which they're allowed to submit data, the possible values the system is willing to accept from them, the state of the system before they're allowed to perform a specific action. The list goes on. Some might view business rules as a contract — a set of acceptable behaviours when interacting with software. Not only are these rules contractual, but they're also enforceable. One thing software developers try to do is to decouple the business rules from the actual code. Not only is this a best practice in terms of separating concerns — what the software does versus how it does it — it also provides a means to change the business rules without changing the software.

What this gives us is a set of policies, business policies that operate independently of the application we've built. When the policy changes, the behaviour of the software changes too. This all sounds great, having a complete separation of business concerns and implementation concerns. But what kind side-effects are we introducing when the business rules aren't interwoven throughout the code? Are we limiting what users can actually do with the software, or worse, are we introducing deadlocks into the system by giving business policies free reign?

Fundamental Policies
If we're to embed a work-flow policy engine into our code, perhaps a good starting point is looking at the basics. That is, what kind of questions can we ask about the overall state of the system? From there, we can ask if this is something we would want to hard-code, or allow as a parameter to the business end of things. For example, let's say I'm building a simple file upload interface. Let's also say that a requirement of the system is that there must be enough disk space to accommodate the new file. The first option: write some sanity-checking code that ensures there is enough disk capacity before the upload is allowed to start. The safe route — you'll never start an upload only to fail half way through.

Now for the second option. Let's say we want to continuously check for disk space as the upload is happening. That is, we don't want to forbid an upload because only 90% of the file will fit. Files are deleted all the time in this particular system we're building. That means there is a good chance the 10% of our required disk space will become available during the upload. This is something we would most certainly want to avoid hard-coding. Not only is this logic experimental, but since it is far from straightforward, it will likely impact other components in our system should we decide to implement it. Could we express this latter option as a business policy?

Let's go back to the first option for a moment, where we're simply checking for space before the upload starts. What if we were to implement this as a policy instead of codifying our logic? That depends, and this is a good question to ask because it forces us to validate our fundamental assumptions about how the system should work. Should the file uploader check once for disk space and fail immediately? How likely is that to change due to other factors in the system and due to user feedback? Apprehension in any one of these areas lead us to rethink our assumptions about more than just the file uploader — how it is connected to other components — can a more elaborate work-flow be supported without major architectural change?

What I find most useful about these mental exercises on what should be hard-coded and what shouldn't is the evolutionary path that you're prepared to support. Maybe a file uploader that checks for disk in-flight is far-fetched and unlikely. But it opens the door to other potential changes and how hard-coding certain scenarios might become a problem. The opposite is also true — too much embedded business policy. Just like the hard-coded logic means stuff is hard to change, so to is overloading code with external business logic.

Rigid Policies
At this point in the development game, we've answered some of our fundamental questions about business policies, and where they're beneficial to the long-term evolution of our software. That's half the battle. The other half is the policies we're designing and how they work compared to coding the same logic using a programming language. Is it really all that different? Can we escape some of the pitfalls associated with programming languages and their paradigms of expressing logic? And this is where problems with rigid business rules rear their head — when we're making an assumption about reduced complexity.

Take rigid rules set forth by a business policy as an example. By rigid, I'm talking about validating the state of something to an exact value — not within a range, or almost equal, but dead-on accurate. Like when the database must be connected. There is no in-between for these types of rules, they either pass the test or they don't. These types of business policies are easy to create and plug into slots we've deemed suitable within the code base. Perhaps a little too easy. Too much freedom for exacting requirements in business work-flow leads to scenarios that are very difficult to debug.

Rules that require a condition of system state are fine on their own, but the whole point of adding a business policy engine to the project is to afford the flexibility of building work-flows incrementally. Stacking one rule on top of another. Instead of achieving flexibility, we're building up a disconnect between the code and the business engine. When everything works, we still have that degree of separation between the pure software components, and the written rules of the business domain. So, if we have fundamental rigidity in our policies, when something does go wrong, it is very difficult to sort out.

Achieving Flexibility
There are two ends of the spectrum when in comes to implementing business policies. The one end gives rules that must match the state of the system exactly in order to resolve as true. The other views business rules as a guidance tool. That is, business rules simply point certain flows of control in the right direction. Consider the business practice of online retailers providing their shoppers with relevant product suggestions. This type of behaviour fits the business policy candidacy quite nicely because it doesn't require exact values that overly-restrict the actions of users. A store needs flexibility, an easy way to tweak this logic.

Business policies shouldn't be too low-level or even expect high-accuracy. There is no real harm in creating plain-old software components that do these types of calculations. They're really good at it. What they're not so good at is taking a pure business principle and applying it within the confines of the software system. Not from an evolutionary perspective at least. It takes software development effort and that equates to time and money. Business policies are a nice way to experiment with different work-flow implementations to gain a competitive edge.

Friday, August 21, 2009

Configuring Trac Ticket Workflow

Trac is a project management system written in Python. Trac has a powerful issue tracking system in which new issues are created as tickets. The system is flexible enough to allow for custom ticket types. This means that Trac tickets not only allow for issue tracking, but any conceivable software development task as well. There are many other customizations that can be made to Trac tickets such as custom fields and custom work-flow. Tickets in Trac go through a series of states during their lifetime. The current state of a given ticket determines the actions available on that ticket. The state of a ticket in Trac terminology is the ticket status. The ticket work-flow that determines the actions available, the permissions required, and the state the ticket must be in in order to transition are all configurable. In other words, if a given ticket is closed, the only available action for the ticket is to reopen it. This is because of the default Trac ticket work-flow configuration.

In the Trac configuration, ticket actions can be configured to allow for certain ticket states to be active in order to execute the action. So, if you wanted to allow more actions other than reopen on closed tickets, this can be specified in the Trac configuration. Multiple current states may be specified as criteria. Only a single target state may be specified. Below is a simplistic example of a ticket work-flow configuration element.
[ticket-workflow]

action = current_state1, current_state2, current_state3 -> target_state

action.permission = TICKET_MODIFY

action.operation = ticket_operation_name

Friday, March 27, 2009

Does Plone really suck as a CMS?

Plone is a content management system written in Python. It is built on top of Zope, a web application frame also written in Python. To identify how well Plone performs as a CMS, we must identify what a CMS is supposed to do and what Plone actually does. Rather than give a rigorous definition of what a CMS is, it is safe to assume that any given CMS is supposed to manage the publishing of content for any number of users. This involves the content work-flow which specifies the various states the content will go through in the publishing cycle. All this needs to be as transparent as possible to the end user because their ultimate goal is to publish content in an orderly manor and as painlessly as possible. These same questions of CMS quality could be aimed at any CMS in existence including TYPO3, and Drupal. Plone often gets misrepresented as a bad choice of CMS, often for the wrong reasons. Many Python developers cringe at the mere thought of using Zope as a Python web application framework. Zope is probably the most powerful Python web framework in existence and the reason for the hesitation is the time investment involved in learning how to use it. Since Plone is built on top of Zope, it relies heavily on not only Zope's functionality, but also the philosophy of how it is used. Flawed software tends to flow upward so Plone will inherit the good, the bad, and the ugly. Thus, some of the complexities found in the Plone user experience are influenced by Zope.

Ultimately, the biggest driving factor in any CMS is the user experience. Everything else is secondary, including the setup of the system. Plone is strong in some user experience areas and weak in others. One of the weak spots in the Plone user experience is the back-end interface which is essentially the Zope interface. For anyone who is using the system for the sole purpose of managing content, this can be very intimidating. In a scenario where an editor of the site is temporarily given the task of managing a few users, this trivial task suddenly becomes a time-consuming challenge. However, that same editor Plone user would excel when it comes to doing his actual job of managing content. Plone offers a great user experience when it comes to general content editing and work-flow management. In fact, the work-flow Plone component is probably superior to many other mainstream content management systems simply because it is very straightforward to use for the people who need to use it. It doesn't require major customization from developers just so that it is barely usable by content editors.

When the case for new custom functionality in the CMS arises, development in Plone is hard. That is, there is a steep learning curve when coming from another CMS or web framework. Again, this stems from the challenges in developing for Zope. The most common reason for custom development in a content management system is to create new content types with new specialized behavior. These new content type may in fact extend the work-flow functionality of the CMS if the work-flow framework will allow for it. Plone also has something call archetypes for extending the available content types in the CMS. The idea behind archetypes is that developers and transform UML modules into functional Plone extensions. This is a very cutting-edge concept that no other CMS offers.

Some of the arguments against Zope and Plone are not well grounded. For instance, a common complaint about Plone is that it is a challenge to install and configure. This may have been the case five years ago but today it is one of the easier content management systems to install. In fact, most of the configuration is taken care of by the installer asking the user simple questions. Another argument is that Zope is very resource intensive. Users must look at why these resources are used and what they get in return. An alternative CMS, offering the the same functionality as a Plone CMS installation is likely to have similar resource consumption. Additionally, a content management system isn't a flimsy desktop application. For any non-trivial CMS deployment, you are going to need modest system resources. This is just a fact of life.

Finally, this isn't a marketing scheme for Plone as a CMS. I haven't used it other than experimentally for years. I think if nothing else that serves as further proof that you need to pick the right CMS for the job. Period. Focus on user experience. Which CMS can you install, setup with the required functionality for the people who manage the content, and deploy the fastest, with minimal complaints from content editors? After asking this question, you may realize that a CMS is not what you want at all and that a plain old web application framework would do the trick after a month of custom development.