-
Notifications
You must be signed in to change notification settings - Fork 3
Best practices
These best practices are related to CFlow only. Since CFlow is in essence a routing engine, these practices will mostly concern configuration. This page assumes you know all about that.
Some general guidelines:
- Only use conventions for small applications that are easy to oversee. In the majority of cases, use configuration. It also allows other developers to gain insight in the flow quickly.
- Define one target per configuration file, and give that file the name of the target.
- Don't create deep directory structures for your configuration. As a rule, go no deeper than one level below your main configuration directory. If possible, put all configuration files in one directory.
If one thing helps you manage a larger application, it's avoiding duplicate configuration. These guidelines help you do that.
- First create the (concept) configuration, then start coding. But of course, don't try to create an elaborate configuration beforehand. Be agile.
- Don't create deep task hierarchies. Although task nodes can contain children that contain children, it is usually, but not always, better to organize children in separate events. This allows you to reuse those events.
- Keep the number of tasks within an event small. Events with many tasks are more difficult to understand, and probably not reusable. Chances are you're going to have to duplicate configuration.
- Although small events are better, let each event be meaningful. Try to let your events reflect something in the real world. If you abstract your events too much, you may end up with a lot of small events, that are difficult to understand and manage. A large number of dispatch tasks is an indicator of this.
- Name your events based on what has happened, not on what its tasks are supposed to do. This sounds easy but is actually quite hard to keep up. This habit helps you to keep events concise and reusable, because it reduces coupling between events (not coupling in code, but 'mental coupling').
Includes are a powerful concept, but they can bite, too. Especially if your application becomes larger, some extra thought should go into the organization of your included targets:
- If a target defines events, don't define tasks for the other phases in that target. Instead, put start and end tasks together in another target, and include that target. Do the same with before and after tasks. However, if you are sure that tasks in other phases really belong to this target only, you can (and should) define them in the same target as the events.
- In principle, let all events in a target be related so they concern one specific thing. Split such a target up into separate targets if you see two or more groups of events, and then combine them using includes.
- Create concrete targets and abstract targets. Concrete targets should only contain includes, abstract targets should define tasks (and have
abstract="true"). All events should be directed to concrete targets. This pattern allows you to abstract task sequences, so you can swap the internals of a target easily. This is especially useful for aspect oriented concerns.
An analogy can be seen between some object oriented concepts and configuration:
- objects --- targets
- methods --- events
- method calls --- dispatching events
- inheritance --- includes
The analogy is of course far from complete. Object oriented programming is a far richer concept, with additional goals. But the analogy is good enough to apply some of the rules and patterns that apply to object oriented programming, specifically to avoid duplication.