Designing Across a
Product Suite.
How patterns, persuasion, and patience compound when you design across a product suite.
Problem, Solution and the Impact that followed.
Problem
Across the Oracle pricing suite, individual products had inherited inconsistent design quality, with shared users moving between them daily. Rate Plans used a generic DS template that wasn't built for the data it carried. Shipping Charge List was being scoped as a single flat table for three structurally different pricing methods. Formulas were modeled as local-to-a-price-list, forcing users to recreate the same logic across every list they touched. The problem wasn't one broken product. It was suite-wide coherence.
Solution
Three projects, three modes of design work:
- Rate Plans — earned the redesign by making the argument visually, then designed three surfaces (authoring + two negotiation fragments) across Pricing, Subscription Management, CPQ, and Order Management.
- Shipping Charge List — shipped solo in 3 weeks by reusing patterns established across the suite, with original design work focused only on the per-tab add flows.
- Formula Management — argued early for formulas as a global entity, accepted the deferral when dev bandwidth wouldn't support it, and shipped the right model the cycle after.
Impact
- Three products shipped across the pricing suite, each addressing a different scale of design work (cross-team, solo, deferred-and-revived).
- Rate Plans delivered as three coordinated surfaces (one authoring, two negotiation fragments) across three product ecosystems.
- Shipping Charge List shipped end to end in 3 weeks via established pattern reuse, with new design work scoped to per-tab add flows only.
- Formula Management restructured the data model from PL-local to suite-global, with usage visibility and selective cascade to dependent entities.
- Patterns originating in the Price List redesign were reused across all three products, compounding the foundational work into faster delivery downstream.
Rate Plans: Earning the Redesign
The product I inherited
Rate Plans was the first product in the pricing suite to migrate to Redwood, done well before I joined. The redesign used a DS template that looked striking: four vertical panels across the screen, one per charge type (one-time, recurring, usage, and so on), each showing a summary of what was configured.
The problem wasn't visible until you tried to use it.

Summary-only meant tunneling for every action. The panels showed what was configured but not enough to change it. Every admin action, whether editing a charge, adjusting a tier, or modifying a rule, required drilling into a separate page, completing the task, and coming back. The main screen was a viewing surface, not a working one. Users lived in the drilldowns and used the main screen as a navigation index.
Two secondary issues compounded this. The layout was fixed, not responsive, so plans using one charge type had empty panels eating space while plans using all four felt cramped. And the underlying DS template was generic, built for a different use case and conscripted into rate plans because it was available at migration time.
Why we couldn't fix it earlier
By the time I joined, my team had been embedding old Rate Plans inside the new Price List for several quarters. Every time we wired up a rate plan surface, the same friction surfaced. We logged it, talked about it internally, and moved on. It wasn't our product to redesign. We didn't have a mandate. That continued for four quarters.
The opening
In the fifth quarter, the Rate Plans product team came with a request: add entitlements to the surface. Entitlements were a fragment owned by Subscription Management, with two sub-parts and multiple setup paths, originally designed for a different ecosystem and now being pulled into Rate Plans. Two more features were planned for the next cycle.
The ask: add entitlements to the existing four-panel design.
We didn't think it would fit. The original four panels were already at the edge of what the layout could hold, and entitlements wasn't a small addition. It carried its own internal structure, its own configuration paths, its own visual weight. Trying to absorb it into a template that already wasn't working for the original task was going to produce something worse than what existed.
So instead of pushing back verbally and hoping it landed, we built the argument visually.
Making the case
We mocked up multiple iterations of entitlements crammed into the existing UI, showing what was lost, hidden, or made worse. We annotated each iteration with pros and cons explicit on the canvas. Alongside those, we sketched what a properly redesigned Rate Plans surface could look like, one that treated rate plans as a working surface instead of a navigation index, and could absorb entitlements (and the two upcoming features) without buckling.
We took both sets into a stakeholder meeting. The visual side-by-side did most of the work. It's hard to argue that a design will be fine when you're looking at a mockup showing it not being fine.

The win, and what we'd actually signed up for
The stakeholders agreed to scope a full Rate Plans redesign, not just a feature graft. We had earned the right to redesign a product we'd been told, four quarters running, wasn't ours to touch.
What we didn't fully grasp in that meeting is that Rate Plans doesn't live in just one ecosystem. It's authored in Pricing, pulled by Order Management for negotiation flows, and now needed to pull from Subscription Management for entitlements. Three teams, three ecosystems, three sets of PMs and designers who had opinions about what the surface should be.
We'd just signed up to redesign the most cross-functional product in our suite.
That's Part 2.
Rate Plans: Designing Across Ecosystems
What we'd actually signed up for
Three teams. Three ecosystems. Three sets of users.
Rate Plans is authored in Pricing. It's pulled into Subscription Management because entitlements live there. It's pulled into CPQ and Order Management because rate plans get negotiated at the moment of sale. The redesign we'd won wasn't a single surface, it was three:
- A new Rate Plans authoring surface for Pricing.
- A negotiation fragment for CPQ.
- A negotiation fragment for Order Management.
Each had its own users, its own conventions, and its own opinions about what should live where.
Fight 1: Where do entitlements belong?
The first disagreement came from Subscription Management. Entitlements are the rules that govern what a customer is entitled to under a given rate plan, things like usage caps, included quantities, overage logic. Without a rate plan, an entitlement has nothing to attach to. They don't exist in isolation.
But the Subscription team wanted entitlements to sit outside Rate Plans, on the main price list page, with a link back. Their argument was about visibility and engineering effort: a separate top-level entity was easier to surface in their flows and faster to build.
For our users, it didn't track. A pricing admin authoring a rate plan would have to:
- Create the rate plan.
- Add charges to it.
- Leave the rate plan surface.
- Go to a separate area on the price list page.
- Author entitlements that point back to the rate plan they just left.
That's not setup. That's hide-and-seek with your own work. Entitlements derive their meaning from the rate plan they belong to. Separating them in the UI breaks the mental model of authoring.
We mocked up both versions, took the combined Pricing + Subscription teams through the user journey, and made the case that the visibility win wasn't worth the cognitive cost. Entitlements moved inside Rate Plans.

Fight 2: Whose patterns serve whose users
The second disagreement was harder, because there wasn't a single answer.
Once we'd designed the authoring surface, the assumption was that the negotiation fragments for CPQ and Order Management would be straightforward lifts, take the rate plan surface, package it as a fragment, hand it over. Same component, two new homes.
That assumption broke the moment we looked at how each team's users actually negotiated.
CPQ users negotiate granularly. A sales rep configuring a quote isn't renegotiating the whole rate plan. They're making targeted edits, adjusting a single tier, applying a discount to one charge, tweaking a usage rate for a specific customer. The fragment they need is one that surfaces individual charges as editable units, fast.
OM users negotiate holistically. An order manager finalizing a deal is often working with the rate plan as a whole, reviewing it end-to-end before committing. The fragment they need is one that exposes the full rate plan in a reviewable state, with edits possible anywhere but no single edit being the main action.
Same data, same product, two completely different working modes. Our authoring patterns weren't wrong for our users, but they weren't right for these users either. Lifting them as-is would have produced fragments that technically worked and practically didn't.
So we deliberately broke our own patterns, sat with CPQ and OM designers to understand how their users actually moved through a negotiation, and designed two fragments that prioritized those flows over consistency with the authoring surface. The fragments share visual language and components with Rate Plans, but the information hierarchy and primary actions differ by surface.

What made it intense
The work itself was complex. What made it intense was the cadence around it.
Subscription Management was building the entitlements component on a clock, every design decision we made fed directly into their development sprint, and the component they built would later need to be translated into our pricing dev stack on a separate one-month cycle. Delays at the design layer compounded across two engineering pipelines. Every meeting that didn't reach a decision pushed the chain back.
And I was the youngest designer in most of those meetings. The PMs and designers across teams were senior to me by years. There were stretches where I worried about being overshadowed, where the easier move would have been to agree and move on. What I learned to do, in real time, was hold ground on the specific question being decided without escalating the conversation past it. Stay on the user. Stay on the task. Bring the disagreement back after the meeting with a refined version of the argument rather than trying to win it in the room.
The team was open. Not a hard wall, but not a free pass either. Convincing them required showing up to each meeting with the previous meeting's feedback already absorbed and answered.
The shipped outcome
The redesign shipped in three deliveries:
- The new Rate Plans authoring surface for Pricing, with entitlements integrated inside.
- The CPQ negotiation fragment, optimized for granular edits.
- The OM negotiation fragment, optimized for whole-plan negotiation.

The lesson I took from this stretch isn't that cross-team design is hard. It's that the patterns you've earned the right to design with aren't the patterns you're entitled to use everywhere. When the user changes, the design has to be willing to change with them, even when your existing patterns work. Especially then.
That discipline, putting their user above your patterns, is what made the three surfaces feel like one product across three ecosystems instead of three different products wearing the same skin.
Shipping Charge List: When Patterns Travel
The product
Shipping Charge List is where price values are assigned to shipping methods, the rules an order management system uses to decide what to charge for moving goods. Same pricing suite, same users as the Price List, smaller scope.
There were three ways shipping methods could be priced:
- Price by Shipping Method (global value, acts as catch-all)
- Price by UOM (Shipping Method × UOM of the item ordered)
- Price by Item (Shipping Method × Item × Item UOM)
The catch-all behavior deserves a callout, and the credit for it goes to the PM. When an order references a shipping method that has no specific price configured against the item or UOM, the global Shipping Method price kicks in and the order fulfills. The order management system gets notified that the catch-all was used, so it can charge correctly downstream. The user's supply chain doesn't break while pricing is being refined. It's a small piece of system design that protects the fulfillment path, and it changed how we thought about the surface.
The PM ask, and the disagreement
PMs wanted a single table covering all three pricing methods, same reasoning as the Items section of the Price List case study: fewer surfaces, less engineering effort. We pushed back with the same argument.
The three methods aren't variations of the same thing. Their setup paths differ, their pricing logic differs, and the attributes that matter on each row differ. Adding a Price-by-Shipping-Method row needs different fields than adding a Price-by-Item row. A single table would either have to flatten all three or carry empty cells across most rows, exactly the legacy-item-table problem we'd already solved once.
We argued for three tabs, one per pricing method, each with its own optimized add flow and table structure.
This time, the argument didn't take quarters to win. We'd already built the precedent.

What got reused, and what was new
Shipping Charge List shipped fast because most of the patterns it needed already existed. From the Price List redesign, we brought in:
- Atom-as-row flat list structure with values inline
- Tabs for fundamentally different types (the item-types argument applied directly)
- Mass actions and rule-based pricing for bulk updates
- The grid escape hatch for Excel-style edits
- Search, filter, and multi-select scaled to the volume
What was new was the add flow per tab. Adding a Price-by-Shipping-Method row is different work from adding a Price-by-Item row, different fields, different validations, different reference data. Each tab got its own purpose-built add flow rather than a single generic one.

Shipped solo, in three weeks
I ran this product end to end, scoping, design, stakeholder alignment, dev handoff. Initiation to final shipped design in three weeks.
That speed wasn't because the work was small. It was because the work compounded. Every pattern Shipping Charge List used had been argued through, validated, and shipped on another product in the suite. The atom-as-row, the tab structure, the mass action surface, the grid, the search-filter-multi-select scaling, none of these had to be designed from scratch or re-defended in meetings. They arrived as defaults.
The lesson
The case study's earlier sections were about earning the right to design. This one is about what happens after you've earned it, in places you didn't expect.
A well-developed pattern is itself a design contribution. The Price List redesign's value wasn't just the Price List, it was that the next product in the suite shipped in three weeks because the arguments had already been made and the patterns were already proven. The new add flows per tab are the only thing that needed original design work. Everything else was reuse, and reuse at this scale isn't a shortcut, it's the payoff for doing the foundational work right the first time.
Formula Management: When the Data Model Is a Design Decision
What formulas are
Formulas are pricing logic. Things like "average of cost for USA and India, plus 12%", or more complex multi-input rules that derive a price from cost, region, margin, and customer attributes. Customers often have a small set of formulas they apply repeatedly across price lists, the same logic shaping prices for different products, regions, and contracts.
The legacy model, and why we questioned it
When formula-based pricing was first being scoped for the new Price List, the inherited model treated formulas as local to a price list. A formula authored in one PL stayed in that PL. If a customer used the same formula across ten price lists, they recreated it ten times.
We pushed back during scoping. Formulas describe customer logic, not price list logic. A customer's pricing rules are about their business, not about which list they happen to live in. Modeling them inside a PL conflated two concepts that should be separate, and it produced predictable downstream pain:
- Data duplication as a maintenance problem. Ten copies of the same formula means ten places to update when the underlying logic changes, with ten opportunities for drift.
- Reusability as a usability signal. Users were doing the same work repeatedly. That's almost always evidence the data model is wrong.
The argument landed conceptually. The team agreed. But there was no dev bandwidth to build formulas as a separate entity that cycle, so the legacy model shipped, with our suggestion noted for later.
This is the part of the story I want to be honest about. The first round wasn't a fight we lost. It was a fight we won on merits and didn't get to act on. Being right early isn't the same as shipping early.
The opening, a cycle later
The team came back when bandwidth opened up. The suggestion was still on file. The next cycle, formulas got their own home.
The design
Three pieces, each addressing a specific failure of the legacy model.
1. A top-level entity. Formula Management became a separate surface in the pricing suite, alongside Price List, Cost List, and Shipping Charge List. Formulas now lived with their owner (the customer's pricing logic) rather than nested inside a downstream consumer (a price list).
2. A "where used" view. The main Formula Management list shows each formula alongside the pricing entities it's referenced by. Clicking Where Used opens a drawer with a table, one row per Price List × Item combination using that formula. Users can see exactly where a formula is in play before they touch it.


3. Selective push to update prices. When a user edits a formula, they can push the change out to consuming entities. The push isn't all-or-nothing. Users select which Price Lists to update, and within each PL, which items to push to. The system previews the resulting price changes before commit.
This was the most important capability to get right. A formula change can ripple across thousands of priced atoms, and an uncontrolled cascade is exactly the kind of operation pricing admins are right to fear. Granular selection makes the cascade safe to use, which makes it actually usable.
The lesson
The conventional framing is that data modeling is engineering territory, and designers come in after the entities are defined. Formula Management is the clearest case I worked on where that framing was wrong.

Where formulas lived in the system was the design decision. Inside a price list, they were duplicated work and silent maintenance debt. As their own entity, they became reusable, visible, and controllable. The UI changes followed from the architecture change, not the other way around. The data model was the design.
Bringing that argument forward early, accepting the deferral when bandwidth wouldn't support it, and being ready to act when the cycle came back around is what made the new design possible at all.
Conclusion
Three products, three different working contexts. Rate Plans was the biggest fight, won by making the argument visually and then carried across three ecosystems with teams I didn't own. Shipping Charge List was the fastest, three weeks from initiation to shipped design, because the patterns it needed had already been proven somewhere else. Formula Management was the most patient, an argument made early, held in place through a cycle where the system couldn't act on it, and shipped when bandwidth came back around. Across a product suite, the design decisions that matter most are often the ones that aren't yours to make. Permission to redesign, which patterns get adopted, where an entity lives in the data model, none of these are unilateral. The work is in shaping them, and the alignment, the persuasion, and the patience aren't preliminaries to the design. They are the design.
The thread that connects the three is compounding. The Price List redesign earned a set of patterns. Rate Plans earned the credibility to argue across teams. Shipping Charge List inherited both, and shipped fast because of it. Formula Management was waiting on the system to catch up to an argument that had already been made. Each project makes the next one easier and the next argument shorter. That's the part of designing across a suite I want to carry into the next one.

