Great toolkits strive to offer a cohesive environment where tasks can be done in a simple and obvious manner. We built the data model in Farseer so that it mirrors business structures in a natural way, by breaking down your organizational units into more specific subunits. This helps you grasp the big picture at first and then drill down into the details if the need arises. The most specific parts of the model are flows which actually represent your data in the form of monthly time series arrays of cells.
This hierarchical model has many benefits as company departments and employee responsibilities align with the data model itself. There are also some drawbacks inherent to this model:
- Parts of the hierarchy might be derived from other parts
- You may want to represent a data point as a calculation of other data points around it
- Time series data in a flow obeys some law or formula and calculates itself, given a starting point
- You want to experiment with your data without actually changing it, to see how it would behave after a business decision or external effect that you can somehow express
- You want to summarize or refer to only certain aspects or parts of the hierarchy
All of these problems can be naively resolved by duplicating parts of the hierarchy into multiple places where they are needed, or doing math by hand and entering the resulting data. This works although it’s tedious, and will probably lead to a cluttered data model in the long run. You would also have to remember to update every copied instance of a data point by hand if it changes.
We’ll cover better ways of solving most of the above shortcomings in this post, and leave 3. and 4. for the next post in this series.
Expressions as the answer
If you look at the drawbacks, it’s obvious that we need a way to make flows smarter. They needn’t hold the actual data itself but merely point to other flows. That would provide a single source of truth, and when the source flow is altered, the changes are reflected in all the smart flows that to refer to it. Then we wouldn’t need to copy anything or update copies when the original data changes, as it would happen automatically.
In Farseer terminology, we can edit a flow’s expression to tell it from where and how should it derive its data. We do this by entering the expression as a valid string that adheres to a number of simple rules which we’ll look at later. Expressions can be thought of similarly as formulas in Excel, with a slight difference – formulas have to be assigned to every individual cell in Excel, and our expressions refer to whole flows.
Expressions are edited in the Expression ribbon of the Flow Manager. Say we want to make a new flow called B and simply reference data from an existing flow called A. We start by typing
A in the Expression editor and see that A is offered in the popup typeahead window.
Pressing the return key substitutes what we entered with
#1. In order to refer to flows in a concise way, they have reference numbers which can be made visible in the View options of the Flow Manager. Flow A has a reference number of #1, and if we point our cursor at it, a description will pop up and show us what #1 means. Flow names can be arbitrarily long, and our more complicated expressions could get hard to read so it’s better to represent them with reference numbers as a shorthand. The typeahead and helper windows provide a way of using expressions without ever having to see reference numbers, but you can also enter reference numbers directly from the Flow Manager if you find that more convenient.
So now we have a new flow B that contains the same data as A. If we wanted to, we could edit data in B. Because references work only in one direction (B refers to A), we can safely edit (or more precisely, overwrite) values in B, and A will not change.
Chained references also work, so we could create a flow C that refers to B. It will get data from B, and B will forward it from A, along with its own overwritten values.
You can also make references to clusters – the only difference is that clusters have their reference numbers in special form, eg
#c21 (notice the c).
Where could this be instantly useful? Say we have five different Sales clusters and flows spread across our business hierarchy. It would be nice if we could see a total of all our sales within our company without compromising the actual hierarchy, and without consolidating other flows and clusters along with them.
We create a new root cluster (at the top of our existing hierarchy) called Sales total. In it, we create five new flows, and make each of them refer to existing sales clusters and flows. After that, we click on the Sales total cluster and voilà, we have our sales total consolidated. Creating five new flows, even if they’re only references does seem a bit too much, does it? Turns out it can be done with only one new flow.
Our Sales total cluster’s purpose is to consolidate stuff we bring into it. As far as we’ve learned, clusters are entities that consolidate all child entities within them, and flows hold data or refer to other flows or clusters. Expressions enable us to bend these notions – we can replace our five new flows with only one, and change our expression to
#2+#c3+#25+#c4+#33. We can also use operators like
* in the same way we use them in regular arithmetic. All of these operators act on matching data points in flows or clusters. So If we write
#1 + #2, it will add the corresponding month values for each of our flows. We can also use constants, like
#1 * 0.22.
Our expression evaluator implements a simple math language which enables you to do everything from napkin math to complex evaluation including functions and variables. You can change operator precedence or just group parts of an expression together for clarity using parentheses, e.g.
(#2 + #3) * 5.
Expressions on different unit types
In the previous example, we’ve touched on the concept of having a Sales flow. Maybe you look at your sales just as financials, but in some cases, you’d rather express it through other means. For example, you could have a warehouse with a number of products, each with its own price. You could multiply (by hand) the number of products sold each month by their prices and enter only financials, or you could let Farseer calculate the financials for you. This offers a finer-grained look at the relation between price and products sold, and also lets you experiment with each of these components to see how changes in price affect your revenues.
Farseer’s clusters have a property called unit type which is basically a way of saying which type of elements inside you want to consolidate. Usually, it’s financials (unit type fin), so only flows and subclusters of that type are taken into account. This leaves space for deconstructing your financial flows, effectively deriving them from flows with different types. The way to do this is by using expressions. We define a new financial flow Revenue and set its expression to
#3 * #5 (meaning number of products sold times the price of this type of product).
There are no rules set on how your unit types interact with each other, i.e. multiplying two financial flows (looking at the semantics, you get a result of type fin2) will not produce an error in the evaluator. You are always left to define the resulting unit type as you want it. This is intentional, as it gives you absolute power of expression to derive your flows as you see fit.
If you’re not sure that your expression is valid, just click the Validate button. There are some cases where expression validity is not that obvious, so let’s look at some examples. Circular validation errors are encountered when the evaluator doesn’t have a stopping point as it hops through references. You could produce a scenario like this if you have two flows A and B, and make them reference each other their respective expressions. This is the most simple case, but you could encounter some less trivial ones when referencing a cluster from within itself, or creating reference cycles from more than two flows. When an expression looks valid but you get an error, a cyclic validation error is the usual culprit to look for.
This post should get you going with Farseer’s expressions. Feel free play with them – they are designed in a non-obstructive way, so you can’t really mess things up by adding a few expression flows outside of your main business hierarchy. In the next post, we’ll be looking at some concrete business scenarios where expressions truly shine, and you’ll hopefully see why they are one of Farseer’s most valuable features.