← Back to Blog
Let's Code: Assembly Organization Using Services
Eric Padua·
Hello friends, and welcome to another blog series! This time, we're going to showcase some design patterns that really leverage the coding capabilities within OneStream.
Now, this isn't meant to be a series of me droning on about how code works in OneStream, or why it works, or what the equivalent computer science lingo is for certain things (I actually started the blog out this way and I said to myself after writing a bunch, "There is no way anyone is going to read this if even I don't want to re-read this in the moment as I review.")
So, I've decided that this is going to be purely a series where I show you how things get kicked off in OneStream based on what the desired actions or outputs need to be when using coding constructs. We'll focus on the "how-to" and the "why-we-use-it," not the dense theory.
The cadence for the series will be random lumped in with any other series types I come up with. It really just depends on what I want to write for the week!
Assembly Finance Custom Calc
Alright, let's set the stage. I want to kick off a finance calculation that is workflow dependent.
Made with Genesis in 2 minutes btw
To do this, I have a finance custom calc service in my assembly that has the specific calculation I want to happen for the entity:
The Assembly
The Files
I also have some code in helper classes (an extender and an XFBR) that get me workflow variables as well as the entity name from the workflow, anticipating that I'll have to get these all the time (reusability, folks!):
Finally, I put some syntax into my data management step (within my workspace) to initiate my service factory (set on my maintenance unit) as well as the specific function I want to kick off.
To get maintenance unit assembly services to kick off, we use the identifier "WSMU" (See below)
The Data Management Jobs
Data Management Step Data Unit Configuration
Data Management Step Business Rule Configuration
Inside the Service Factory
This is where the magic happens. When I execute my DM step, OneStream's backend goes to my service factory's
switch statement and feeds it my function name (which will come in as ServiceCalc), which is passed through the itemName parameter.The itemName instantiated through the Assembly Service instance
Upon execution, OneStream's backend also feeds the service factory the type of service (in this case, a finance custom calc service) that was kicked off, again along with the function name via the
itemName parameter.Since the code under this
case signifies "create a new ServiceBlogCalc class" (which is coded out in a finance custom calc service file named ServiceBlogCalc.cs), it proceeds in kicking off any code in that class.Inside the Finance Calc File
Now we're in the
ServiceBlogCalc.cs file. We have our functionality split out into clean, readable methods.Split out function
For the kick off of the XFBR, we call the helper class to retrieve those workflow variables for us and manipulate the workflow name to get us the raw entity that is attached to the data unit configuration for the data management step above.
Functionalizing Workflow Variable Retrieval
Gets the entity for dynamic call on the Data Management Step
And from there, the finance calc kicks off based on the DM step's data unit configuration, just as any "normal" finance business rule would and puts the 100 where I want it.
"Seems like a lot of steps, sir"
I know what you're thinking. And yes, it is a few steps (and probably a lot of mental gymnastics to follow). But if we do it this way, we can have as many finance calc files as we want. We just use the
itemName to pick which classes to kick off (which can all be 1-1 with the files).There's a squiggle because I just made up another class and it's mad that it doesn't exist
That's probably not intuitive either, so let me explain with a common scenario that I am sure has happened to most of you:
-
Project Manager: "Hey everyone, we have three different model calculations to code out. We'll split the work amongst ourselves throughout the project, along with all the reporting artifacts that we need to build."
-
Assignments: "Model 1 is assigned to Person A, Model 2 is assigned to Person B, Model 3 is assigned to Person C."
-
(Everyone goes off to complete their tasks)
-
(Person A finishes building their portion of reporting artifacts and begins work on Model 1 in the singular "FinanceCalcs" business rule for all the models. They save their work midway to test.)
-
Person B: "Oh no! All the work that I have been coding out is GONE after clicking back into the file!"
I'm sure most of you know what happened here. And at least one person is grinning and telling me that I should just "get the lost code in the audit tables."
But why? Why should I have to do that? Why should we risk overwriting each other in a massive, monolithic business rule?
When we can have separate models in separate files and separate classes in Assemblies, allowing us to delegate people to files so we don't run over each other.
And while we're at it, why not have everything related to the functionality we're developing in one assembly, in one workspace, with those same separate files, with all the functionality extremely portable from the get-go for easy migration?
It's worth it
The assembly concept drives us closer to tried-and-true computer science concepts (that I promised I wouldn't bore you with), but the consequence of this is massively increased scalability, increased maintainability, and far better collaboration.
When OneStream comes out with version control on assemblies, this entire setup will be even better.
I highly recommend coding things out this way for everything (not just finance custom calcs). It has made everything coding-related that I do in OneStream so much easier.
Happy coding, friends.