I want to talk about the intersection of telecom billing, Java EE, GWT, and Salesforce.com — a combination so thoroughly mid-2013 that it should come with a moodboard of flat design launching and everyone arguing about whether responsive CSS was a fad. But here’s the thing: I shipped real software in this stack for real telecom operators who processed real money. And a non-trivial amount of what I learned in that environment is still applicable today, because the underlying problems are structural, not technological.

BluLogix built the Cloud Innovation Suite — a cloud billing platform for telecom operators. My job was backend development, front-end supervision, BPMN workflow design, and, most instructively, integrating CIS with Salesforce.com via Talend ETL. That last part is what I want to spend most of this post on, because it was where the engineering got genuinely interesting.

What telecom billing actually looks like

Before you can understand why Salesforce integration is hard for a telecom billing system, you need a rough model of what telecom billing actually is.

Telecom billing is not an invoice. It is a system that continuously rates events — calls, data sessions, SMS messages, API calls, cloud resource consumption — against a product catalog, applies pricing rules and discounts, manages subscription state, handles mid-cycle changes (plan upgrades, pro-rated billing, add-ons), runs recurring charges on billing cycles, generates regulatory-compliant invoices, processes payments, handles disputes, and produces revenue assurance reporting. The billing cycle for a single enterprise customer might involve tens of millions of usage events, a product catalog with hundreds of rate plans, multiple currencies, and tax jurisdictions spanning multiple countries.

This is why telecom billing systems exist as a specialized software category. You cannot do this in a spreadsheet. You cannot do this in QuickBooks. The data model is radically different from general-purpose financial software.

GWT — Google Web Toolkit — was how you built rich web interfaces in Java in 2013 if you wanted your UI code to be type-safe, testable, and written by Java engineers who were not required to know JavaScript well. You wrote Java, GWT compiled it to JavaScript, and your IDE’s type checker worked across the entire stack. In 2013, before TypeScript existed and before modern frontend frameworks had matured, this was a genuinely reasonable trade. The output JavaScript was verbose and the debug cycle was slow, but the developer experience for Java-centric teams was better than the alternative: raw JavaScript that your Java engineers would treat with the same level of enthusiasm they had for PHP. GWT is dead now. That’s fine. In 2013, in a Java EE shop building enterprise software, it was the right tool.

Why Salesforce hates your billing system

Salesforce’s data model is built around a CRM abstraction: Accounts, Contacts, Opportunities, and Products. This model works brilliantly for sales processes. It is a miserable fit for telecom billing.

Here’s a specific example. In Salesforce, an Account is a company. An Opportunity is a potential sale. A Product is a thing you sell. Once the Opportunity closes, it becomes an Order, and the Products become part of that Order.

In a telecom billing system, a “customer” might have multiple accounts (one per subsidiary), each with multiple subscriptions, each subscription potentially comprising multiple service bundles, each service bundle containing multiple rated components with different billing cycles and pricing tiers. The relationship between “what the sales team sold” and “what the billing system is rating and invoicing” is many-to-many in ways that Salesforce’s standard objects simply don’t represent.

When you’re asked to integrate these two systems — CIS on one side, Salesforce on the other — the first phase of the work is not technical. It’s taxonomic. You spend weeks mapping Salesforce concepts to CIS concepts and documenting where there is no mapping, where the concepts are only approximately equivalent, and where the mismatch is so fundamental that you need to create custom objects on one side or the other.

Specifically at BluLogix, we were using Talend Open Studio for the ETL layer. Talend is a visual ETL tool: you build data flows as directed graphs of transformation components, and Talend generates the underlying Java code. The visual model is useful for stakeholders who need to understand and approve the integration logic. The generated code is what actually runs. The mismatch between “what the stakeholder approved in the visual model” and “what edge cases the generated code hits at 3am on the first day of the billing cycle” is where you earn your salary.

BPMN for billing workflows

The CIS platform used BPMN for its business process definitions — not coincidentally, the same workflow model I’d later use at Talentera with Camunda. Telecom billing has complex conditional state: a subscription can be active, suspended (non-payment), suspended (customer request), terminated, ported, transferred. Transitions between states have business rules: you can’t reactivate a terminated subscription, suspension for non-payment triggers a different re-activation flow than voluntary suspension. These rules differ by jurisdiction and by product type.

BPMN is the right modeling language for this. The alternative is hardcoded state machine logic embedded in the billing engine, which means every rule change is a code deployment. With BPMN, changing the suspension-to-reactivation workflow for a specific regulatory market is a process definition deployment, not a code deployment. Your compliance team can review the BPMN diagram directly rather than reading Java. This is not a theoretical advantage — compliance review timelines are measured in weeks, and “we need to redeploy the billing engine to update this workflow” adds weeks to every compliance change.

The Spring Security layer handled access control across the billing platform’s internal services. Spring WS covered the SOAP service interfaces — in 2013, SOAP was still the lingua franca for enterprise integration, and the larger telecom operators your platform was targeting had middleware that spoke SOAP and expected WSDL. The GWT frontend talked to Spring MVC endpoints. This was standard Java EE architecture of the period. Boring by design.

The ETL work that actually mattered

The Talend-based Salesforce integration had one core requirement: when a sales deal closed in Salesforce (Opportunity moved to Closed Won), the corresponding subscription and billing configuration needed to be created in CIS without manual data entry. Manual data entry in telecom billing is where revenue leakage happens. A missed discount configuration, a wrong billing cycle date, an incorrectly configured product bundle — these aren’t bugs that cause the software to crash. They cause incorrect invoices. Incorrect invoices generate disputes. Disputes cost time and erode customer trust. In telecom, where enterprise contracts run to millions of dollars annually, incorrect invoicing is existential.

The Talend job that handled this ran on a schedule, polling Salesforce via its SOAP API (later REST API as Salesforce expanded its API surface), pulling Opportunities in Closed Won state that hadn’t been provisioned in CIS yet, transforming the Opportunity and associated Product data into CIS subscription objects, creating the billing configuration, and marking the record as provisioned. The error handling was more complex than the happy path: partial failures needed to be retryable without creating duplicate subscriptions. Salesforce’s concurrency model for bulk operations needed to be respected. The CIS transaction model needed to ensure atomicity across the subscription creation and billing configuration.

The part nobody told me going in: Salesforce’s data model is more variable than its API documentation implies. Different Salesforce orgs, configured by different admins over different periods, have different field layouts, different custom fields, different validation rules. An integration that works perfectly against one org needs to be re-verified against every org it’s deployed to. We built a validation step into the Talend job that verified the source data shape before attempting transformation, so failures surfaced as data quality errors rather than as corrupted CIS records. That validation step saved us approximately one data incident per deployment.

The thing about shipping to paying telecom customers

There’s a category of engineering experience you can only get by shipping to customers who will call you if something goes wrong. Not file a ticket. Call. Telecom operators have operations centers. When billing is broken, someone in that operations center knows it, and they know who to call, and they call.

The accountability that creates is clarifying. You do not ship speculative infrastructure. You do not ship things you can’t monitor. You build the operational tooling before the feature, because you know someone is going to call and you need to be able to give them an answer in ten minutes. The standard of care in telecom billing is genuinely higher than in most SaaS categories, because the cost of being wrong is quantifiable to the dollar.

I processed real telecom billing events. I shipped an integration that moved real customer data between a billing system and a CRM. I did it in GWT and Java EE and Talend and BPMN, with Spring Security and Spring WS and an XML-heavy world that now seems ancient.

The world is not that different. Salesforce still has the same data model mismatches with every specialized system it tries to integrate with. Billing systems are still event-driven state machines under the hood. BPMN is still the right tool for compliance-driven workflows. The technology stack changed. The problems are the same.

I know how to work in the old stack. I know why it made the choices it made. That’s rarer than it sounds.