From the first round of employees, Andrew and Evan have both been at Aforza for 3 years, and continue to sit at the heart of our innovation. They were friends from university with Aforza Chief Product Officer, Nick Eales, and drawn to the company by both our vision and the chance to solve complex industry problems.
One of the most pressing problems for Consumer Goods companies in recent times has been omnichannel pricing. In this blog, we’ll go behind the scenes with the engineering team to understand how they approached the challenge, some of the issues they encountered and how they overcame them.
Now, over to Nick Eales, Andrew Ridout and Evan Price.
Andrew Ridout
Nick Eales
Evan Price
Let’s kick things off with an easy one: what brought you to Aforza?
There’s two major things: relationships we get to foster in the team and the opportunity to work on something new.
Start-ups mean there’s no existing code base we have to work off of; we can write all our code from scratch and forge an untrodden, new path with the technologies and the engineering practices we want to use. This means we take what we’ve learnt from prior work and apply it to something totally new.
Even now, there’s still that same ethos of flexibility that we had in the early days; taking modern methodologies and applying a human-centred approach to be able to have the agility and autonomy to move past legacy ways of working. We still aren’t constrained by dated engineering practices, or a “this is how we’ve always done it” approach – anyone can bring their ideas to the table.
Knowing we wanted to build a modern cloud platform to power Aforza’s off-Salesforce solution, we spent considerable time evaluating our options: AWS, Azure & GCP. We had the autonomy to take the time to do that evaluation and pick the best solution. Leadership always trusted us to make those decisions, as opposed to a more rigid, top down ‘it has to be this or that way’ approach.
We’ve also had the opportunity to build and pick up React Native and architect, from scratch, a modern cloud solution on GCP – expanding all our skillsets. And, because we knew we wanted microservices running on Kubernetes, we were able to make the decision to go with GCP. When we moved over to Aforza, in the early days, we hadn’t even spoken of concepts like big data or machine learning. It just became a natural stepping stone.
It’s been really exciting to be able to hire people who not only have experience but also want to help us make decisions – to not just be another cog or head in the masses taking direction. We’re providing an opportunity to make real, significant changes to a product that can, and does, impact consumers’ lives across the world.
Why is omnichannel pricing so important in the market today?
In today’s market, we know customers expect to do business on their terms. This means that Consumer Goods companies need to offer the same consistent experience on every channel. One of the most important things to keep consistent is the ordering experience. This means consistent products, pricing, promotions and discounts whether placed in the field, online or via a telesales agent. Keeping all of these areas aligned cross-channel was the challenge.
Originally, we had two pricing engines – one built on Salesforce in APEX and one on our React Native mobile app, in TypeScript. This meant that there was double the engineering effort to add new features. We were endlessly testing both engines to ensure the logic was the same, and we were constantly finding discrepancies and bugs. We were wasting days, if not weeks, and it was proving to be so, so difficult to guarantee that a rogue difference in rounding wouldn’t cause an avalanche of knock-on effects. At one point, there was such constant walking between Evan and Nick’s desks as they tried to keep the two routes aligned that the carpet wore down.
It was vital to be able to stop going down that route and reconsider the way the whole engine should be structured. We knew we needed a single codebase that both Salesforce and the mobile app could share, but how could we achieve this and ensure that it can still work natively offline on mobile? We decided to refactor the mobile pricing engine implementation into its own standalone npm package. The mobile app could pull in this package and run it, but Salesforce couldn’t. It needed API (Application Programming Interface) microservices to operate, using HTTP requests (which presented a new challenge). It introduced latency within the Salesforce application, so we still had to make it perform while ensuring that there was no impact on user experience.
When we first wrote the pricing microservice, we were sending JSON (JavaScript Object Notation) payloads a quarter of a million lines long. With so much data to send across the wire, and so much logic to run the incredibly complex discounting rules they were causing way too much latency between requests from Salesforce and responses from the service. To overcome this, we went through a huge de-duplication effort to slim down the request payloads which massively improved the roundtrip response times.
The Aforza R&D office where Nick and Evan walked back and forth. June 2019.
Can you tell us about some of the key challenges you faced when attempting to build an omnichannel pricing solution?
Evan
When we had first started the coding and I was developing the mobile side, I’d made a few decisions that just weren’t working out. A month in, eager to prove myself, I realised late at night after weeks of working late to get results that I was going to have to start from scratch. Take a clean slate with a totally different approach. I undid all my work and within days had a working engine that basically mirrored what Nick had already done on Salesforce.
I was 100% supported, as it was only me writing it (although I was liaising with Nick). There was no pressure from anyone saying that I’d wasted my time. It was the right thing to do. We don’t have a blame or ego-driven culture. If it isn’t working, it isn’t working and sometimes you do need to take it back to the drawing board.
Andrew
Early on, one minor error or inconsistency in the implementation could cause bugs, and you’d waste so much time trying to figure out where the mistake was – which engine is the source of truth. “Penny-Perfect Pricing Paul” was an early in-office mascot/indicator of whether there were bugs or not. Happy face on the whiteboard if we’d hit a milestone and a sad face if we had a bug to deal with. In the early days, Penny Perfect Pricing Paul was sadder more often than he was happy!
Penny Perfect Pricing Paul (PPPP) smiling with success. August 2019, Aforza R&D office.
How did you approach these challenges as a team?
When we decided that this was the route we wanted to go down, we knew that we had to take the code from the mobile app and use that as the basis. But it wasn’t as simple as copy and pasting; there’s a huge amount of due diligence required to figure out all of the touchpoints, what to pull out and refactor etc. Plus, there was a hell of a lot of code. Despite our technical breakthroughs, the product still wasn’t production ready or usable from a UX standpoint.
None of it was unit tested. It took us weeks to unit test, which was very different from a big corporation who might just throw the software out without testing or thorough due diligence. We wanted to test all the different scenarios and discount rules and that they were all applying in the correct order to ensure we didn’t introduce new bugs from the ‘lift and shift’ process.
The other main challenge was the Pricing Service API. Initially, we tried to keep it as simple and “dumb” as possible, but this approach meant we had huge request payloads being sent from Salesforce which introduced massive latency. This was demotivating, knowing it meant there were months more work ahead of us to get the service into a performant state. To overcome this, we had to refactor the Pricing Service API into a more complex mapping layer, which meant we could slim down the request payload being sent from Salesforce and minimise the latency. Luckily, we had Nick’s full support to do this refactor even though it meant a lot more work.
From a personal perspective, why are you proud of solving this challenge?
Andrew
For me it’s two things. This omnichannel pricing engine isn’t the only one we have now. We’ve now got centralised engines for promotions and segmentations as well, with a strategic approach across other areas. I think, to date, all of our customers combined have done millions of orders. Knowing that they’ve all been through our code every time they add something to the cart is really rewarding.
Evan
Genuinely, the 3 of us are beyond proud to have created this product from scratch and for it to be used for such huge numbers of customer orders. We created it from nothing.
Looking ahead, what’s next for your teams at Aforza?
We’re always thinking about how we can use our engine approach in more places. It’s the difference between a feature and a true platform, and key to how we scale success for our customers. And, as we deploy in more markets around the world, we’re seeing new requirements from our customers, such as complex hierarchical tax support. It’s great to know we only have to implement this in one place, instead of across two separate engines in Salesforce and mobile.
In the areas of Digital Asset Management (DAM), we’ve built a brand new engineering team – solving new problems just as we did for Retail Execution (REX) as a greenfield project for DAM. We have new team members carving their own paths.
Aforza is an exciting place to be. There is always an opportunity to work on something new, alongside expert Software Engineers, and make a real impact. With the right attitude, you can turn your hand to any challenge and there’s always support to test your ideas. Everyone that comes through our door is investing their skills in Aforza, and so are we.
