The Engineer in the Room
Creating a performance indicator used to require a BaxEnergy programmer sitting with the client. I designed the module that removed them.
Every formula came with a person
Building a KPI meant a BaxEnergy engineer working alongside the client. Every time. The difficulty sat in the software, not in the people using it.
Two users. One screen.
Operators who know exactly which formula they want. Clients who may never write one. Most configuration tools pick a side and quietly fail the other.
My first version drowned them
One form, every field open at once. I rebuilt it as three stages disclosed in order, and Preview stays disabled until the required fields are filled, so the sequence isn't a suggestion.
The shortcut shows its work
Quick Examples hands a first-time user a working formula, and displays the expression before they apply it. A preset that hid its maths would keep them dependent on presets.
It tells you what it threw away
The preview reports its own coverage before you commit. A formula can be syntactically perfect and still be worthless because your conditions threw away half the year.
Wrong syntax fails loudly. Wrong filters don't.
That asymmetry is why the expression is free-form and the conditions are a fixed list. A malformed expression produces nothing. A badly-chosen filter produces a number that looks completely reasonable and isn't.
The step that isn't about the KPI
Designed · not shipped
A save-time review with two toggles, neither of which changes the indicator. It exists in the design file and did not ship in v1.
Constraint is the feature. An unconstrained formula editor is a support ticket with a text field.
The Engineer in the Room
Formulas without a formula writer
Creating a performance indicator used to require a BaxEnergy programmer sitting with the client. I designed the module that removed them, and, for the clients who could never have written a formula anyway, made sure they never needed to.
What a KPI is here
Farsight monitors wind, solar and battery assets. Every machine emits signals: rotor speed, internal temperature, external temperature, blade speed. Raw telemetry: useful, blunt.
A KPI is a formula built on top of those signals. Multiply temperature by a value, divide speed by another, and you get something the raw feed can't tell you.
The objective of a KPI is to extract insights that aren't available to the naked eye: insights that only exist once the data has been worked.
That's the product problem. The design problem is that a formula is a formula, and the people who need the answer are not always people who can write one.
The engineer in the room
In the previous product, creating a KPI meant a BaxEnergy programmer working alongside the client to build the indicator and its expression. Every time. Clients needed a great deal of technical support, and the difficulty sat in the software rather than in the people using it.
That is the thing this module exists to delete.
Worth saying plainly: I wasn't the bottleneck, and neither was design. The old software was.
Two users who share one screen
Farsight has operators who know exactly which formula they want and can write it. It also has clients on the basic tier who may never write a formula at all.
Most configuration interfaces pick one of these users and quietly fail the other. Simplify for the novice and the expert is trapped; expose everything for the expert and the novice bounces.
I gave them different routes through the same screen, and a way to cross from one to the other.
The first version was wrong
I built it as a single form with every field open at once: scope, signals, expression, validation, all visible together.
Looking at it, it was obvious a user would drown. Too much to hold at once, and no signal about what to do first. So I rebuilt it as three stages, disclosed in order.
Define KPI
Technology, target, output unit, name, expression name, time aggregation, description.
Define Logic
The conditions that filter the data, and the expression that combines the signals.
Validate
Pick assets, pick a date range, preview it against the real feed.
The screen splits in half: build on the left, watch it run on the right, as a chart when you want the shape, a table when you want the numbers.
Small things carry the sequence. Expression Name auto-prefixes from your first two
choices, so picking Wind and Asset produces Wind.Asset. and the naming convention is
generated by the interface rather than policed after the fact. Time aggregation defaults to
Baseline, which means don't. And Preview stays disabled until the required fields
are filled, so the order isn't a suggestion.
Quick Examples is the on-ramp
There are two ways into an expression, and they serve the two users.
Quick Examples is for the person who doesn't yet know what they're building. Open it and pick from a list grouped by the technology you work in: Capacity Factor, Lost Production, Turbine Performance for wind; Yield, Irradiation, Inverter Efficiency for solar. Real performance measures, not raw readings, and a solar operator is never shown a turbine formula.
The decision is that it doesn't hide the maths. Before you apply anything you see the expression you're about to get, tagged with its technology, scope and unit:
A preset that concealed its formula would leave the user permanently dependent on presets. Showing it means the fifth time someone reaches for Quick Examples they can read the pattern, and the sixth time they can change it. It isn't a shortcut around the expression editor. It's the ramp into it.
The Glossary is a language reference
The other way in is for someone who knows exactly what they want. That's the Glossary, and it documents FQL (Farsight Query Language), built on the IEC 61850 and IEC 61400-25 standards. Six tabs: attribute reference, functions, aggregation functions, operators, a browsable signal library, and existing KPIs.
Two parts of it carry the whole thesis.
Context variables. A formula can reference CutIn,
CutOut, NominalPower, RotorDiameter, and these are injected
automatically from the asset's own configuration. The user writes a formula about a
turbine without having to know that turbine's specification. That is the engineer's job,
done by the system instead of by a person.
KPIs reference other KPIs. Saved indicators are available inside a new expression, so a KPI isn't a leaf; it's a building block. You can compose on top of work that has already been validated instead of starting from raw signals every time.
Designing the documentation surface for a query language (inside the tool, at the moment of use, for people who are not engineers) is the part of this project I'd want to talk about longest.
Four items in a dropdown
Stage two isn't only an expression. Above it sits Conditions: a fixed list that decides which data is allowed into the calculation at all.
No Curtailment is the one I'd point at. Curtailment is when the grid operator instructs a farm to stop producing. Those hours are not underperformance; they're compliance. Leave them in a performance indicator and the asset looks broken when it was doing exactly as told.
This is a fixed list, deliberately. Conditions aren't user-composable the way expressions are, because getting them wrong is silent: a badly-formed expression fails loudly and produces nothing, while a badly-chosen filter produces a number that looks completely reasonable and isn't.
How you know it worked
The preview isn't a rendered chart and a hope. It reports its own coverage.
972 of 1887 datapoints included · 915 excluded
- Excluded Turbine not available
- Excluded Windspeed below threshold
Schematic. The totals are from a real preview: 972 included, 915 excluded, 1887 sampled. The distribution across the window is drawn rather than measured, to show the thing the count alone hides: exclusions arrive in clusters. A fortnight of downtime and a spell of low wind are not the same problem, and a single percentage cannot tell them apart.
Underneath the chart, every row of the sample carries a status and, when excluded, the reason, beside the raw signal values that produced it.
That number is the honest one. A formula can be syntactically perfect and still be worthless because your conditions threw away half the year. Most tools show you a clean line and let you discover that in production. This one tells you while you're still deciding.
Those reasons are written as sentences, not error codes, and that was a decision rather than an
oversight. ERR_AVAIL_0x02 would move the cost of understanding from the person who
built the system to the person using it, which is precisely how an engineer ends up back in the
room.
How you know it didn't
There are two ways to be wrong here, and the design treats them very differently.
Wrong data is handled well: conditions that exclude too much are surfaced as a count and a per-row reason, in the preview, before you commit.
Wrong syntax is not. A malformed expression reports only that it is incomplete, not where. For the expert this targets that's often survivable, since you know what you were reaching for. But a misplaced parenthesis is a slip, not a knowledge gap, and a slip currently has nowhere to go except the support path this work exists to close.
That's the next increment, and I'd take it before anything else.
What I took away
Nothing is hidden that a user might need, but the module is deliberately not a blank canvas. The order is fixed. Composition runs through a glossary. Duplicate formulas are impossible at the formula level rather than the name level, so two people can't reach the same calculation under two labels and leave someone to reconcile it later.
Constraint is the feature. An unconstrained formula editor is a support ticket with a text field.
The step that isn't about the KPI
Designed · not shipped
Rather than saving straight from the form, I designed a step that appears on save and handles the two decisions that aren't about the calculation: whether the KPI goes live at all, and whether it back-fills from historical data so it arrives with a chart behind it rather than an empty one that fills up over the following weeks.
Authoring and deploying are different decisions, made in a different frame of mind. Merging them into one form is how people ship things they meant to keep as drafts.
Neither has been built. I still think both are right.
Where it stands
Shipped and live, on version one. I've watched people across different parts of the business use it in front of me; every question raised in the demo was resolved on the spot, and there's been no negative feedback from clients.
I don't have usage data, and I'm not going to claim I do. What I can defend: this is considerably simpler than what it replaced, it takes a user from nothing to a working indicator without a specialist beside them, and it respects the difference between someone who knows the formula and someone who never will.
- Role
- Lead Designer · research, information architecture, interaction, prototype
- Design + research
- 5 working days
- Status
- Shipped, version one
- Evidence
- Internal demo across business units, all questions resolved, no negative client feedback · reported, not measured
- Tooling
- Figma; prototyped in Claude Code and run against design-critique passes to catch UX errors before development