Skip to main content

20 posts tagged with "functional-programming"

View All Tags

The Most Dangerous Code Has a Save Button

· 11 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 20

On a Thursday, someone on the finance-ops team opened the admin panel to update a tax table. A new state rate had taken effect: 7.25%. They found the field, typed 7.25, clicked Save, and moved on to the next row. The system stored tax rates as decimals, so 0.0725 meant seven and a quarter percent. The field took 7.25 at face value. For the next two days, every order shipping to that state was taxed at seven hundred twenty-five percent. The first customer to complain had been charged more tax than the price of the goods.

Nobody deployed anything. No pull request was opened. No test ran. No reviewer looked at it. The most expensive behavior change the business made that quarter went out with less scrutiny than a one-line typo fix in the codebase would have received.

This is not a story about a careless employee. It is a story about a system that decided, somewhere along the way, that this particular kind of behavior change did not count as code, and therefore did not deserve any of the protection we give to code.

Name the Dragon

· 14 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 19

There is a system with four thousand tests; all green. They have been green for months. CI is fast, the team trusts it, deploys go out daily, and nobody is embarrassed to say the platform is well covered. Yet, it just shipped a refund larger than the original charge.

That sounds like a testing failure, and in the shallow sense it is. Somewhere there should have been a test that caught it. Somewhere there should have been a case, an assertion, a fixture, a fake payment, a mocked refund, a regression test with the right numbers in the right columns. But that is not the interesting failure. The interesting failure is that the rule was never a thing the system could point at.

A refund cannot exceed the settled charge. Simple sentence. Obvious sentence. The kind of sentence everyone in the room agrees with as soon as the incident review begins. And yet, before the incident, where did that sentence live? A little of it lived in the refund service. A little of it lived in an admin form. A little of it lived in a database constraint. A little of it lived in the payment gateway integration. A little of it lived in the memory of the person who last fixed the related bug. To test the rule, you had to drive the whole platform from the outside and hope the dragon wandered into view.

What Time Is It?

· 12 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 18

A customer adds a jacket to their cart on Friday night. It is on promotion: 30% off, a weekend sale. They get distracted, come back Monday morning, and check out. What do they pay?

There is a correct answer, a defensible answer, and the answer the code actually gives. In a surprising number of systems those are three different numbers, and the last one was chosen by nobody at all. The code's answer turns on one small decision made deep inside a pricing function: when that function needed to know the time, where did it get it?

Exactly Once Is a Lie

· 11 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 17

You send a command to unlock a door; not a metaphor, an actual lock, on an actual door, opened over the network because a tenant is standing outside it and your service has decided to let them in. The command goes out. Somewhere between your server and the lock a packet is lost — not the command, the acknowledgment. The lock opened. The confirmation never came back. From where your code stands, the operation has no result. The safest-looking move, the one every retry policy in the world will make, is to send the command again.

Whether that second command is harmless or a small disaster was decided long ago, not by the network, but by whoever modeled the operation. And the same question hides inside far more than the state of a lock. Provision a server, and a lost reply means you pay for two. Issue a customer the license they bought, dispatch a shipment, send a notification, publish a post, grant a permission… Every one is the same operation: an effect that leaves your control and cannot be pulled back, reached across a channel that can lose the receipt.

Large Action Models Need Small Action Surfaces

· 13 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 16

A language model can answer a question. An action model can do something about it. That distinction is going to matter more than most commerce platforms are ready for. Whether the term is "agent," "large action model," "task-specific AI," or something else that marketing teams have not finished sanding down yet, the direction is clear enough: software will not merely describe commercial options to buyers, operators, partners, and employees. It will increasingly select actions, call tools, negotiate constraints, and attempt to move workflows forward.

In commerce, "move the workflow forward" is not a harmless phrase. It might mean reserving inventory. It might mean accepting a substitution. It might mean committing an order, issuing a refund, changing a shipping promise, requesting a quote, applying a contract price, cancelling a shipment, or escalating a return. These are not generic software actions. They move money, create obligations, expose data, affect inventory, alter customer trust, and (should) leave evidence behind for someone else to explain later.

A Case for Capabilities

· 8 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 15

Operators preparing to support agentic commerce will eventually have to talk about protocols. That may mean MCP, UCP, a marketplace-specific interface, a procurement network, a partner API, or something that has not yet settled into a standard. If they start with a protocol, the first questions tend to be mechanical. Which tools do we expose? Which existing endpoints map to those tools? What schema does this protocol expect? How do we authenticate the caller? How do we serialize the response? Those are all necessary questions, but they are boundary questions. They deal with the outside edge of the system. The deeper question is whether there is a coherent business capability behind that edge.

The Aggregate Cost of Composition

· 10 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 14

Most engineers don't wake up at 3am thinking about chargebacks, but most commerce operators eventually do. A chargeback has a way of turning a small, messy edge case into an expensive, cross-functional incident. Support gets involved. Finance gets involved. Someone pulls logs. Someone else pulls warehouse records. Payment provider screenshots are taken. A bank is now part of the conversation. Whatever the customer's original question was, it has been upgraded from "help me understand" to "prove it." No matter who wins that proof point, the merchant is stuck with the cost of proof.

That cost is not just the refunded transaction. Often, the expensive part is the work required to reconstruct the story. The customer says they were charged twice. The payment provider shows one authorization, one capture, one retry, and maybe a reversal or refund depending on which screen you are looking at. The order management system says the order was accepted. The warehouse says it shipped. The carrier says it was delivered. The promotion engine says the discount was valid at checkout. The customer's email confirmation preserves a total that was true at the moment it was sent. The ledger preserves a different total after tax, shipping, substitution, split shipment, cancellation, or refund logic had its say. Everyone may be telling the truth, locally, and still no one can answer the customer's question cleanly.

It Was Never about the Money

· 9 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 13

The total comes back as 59.666666666667, and somewhere downstream we must ensure that we don't end up with 59.67ontheinvoiceand59.67 on the invoice and 59.66 in the ledger.

The instinct is to reach for more precision. But precision was the easy part. A drifting penny is a symptom. The disease is poor modeling. "Money is not a number. Money is a number plus everything we forget to carry with it."

When Good Enough is Not

· 12 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 12

A purchasing manager needs 200 units of a replacement part delivered to a job site by Friday. The budget is already approved. The supplier must meet a certification requirement. Substitutions are acceptable, but only if they preserve the tolerance class and do not change the installation procedure.

A person can work through that situation even when the systems involved are messy. They can search a supplier's site, read a product page, notice a message like "usually ships in one to two weeks," and decide whether that is worth a phone call. They can ask whether the warehouse really has enough stock. They can ask whether a substitute part is equivalent. They can judge whether the shipping estimate is conservative or risky. Human beings are very good at operating in the gaps between what a system says and what the business actually means.

Is the FP Juice worth the Squeeze?

· 5 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 11

Adopting functional programming isn't free. It requires training investment, a shift in team culture, and a willingness to tolerate an awkward middle period where the codebase is neither cleanly imperative nor fully functional. So the honest question — the one that belongs in a technology leadership conversation — is whether the benefits actually justify the cost.

This is my attempt at a direct answer, organized around the risk categories that tend to matter most in enterprise commerce organizations.

When MVPs Grow Teeth

· 6 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 10

Bad models are rarely designed by teams on purpose. Most of the time it's the model you get by being pragmatic: shipping an MVP, and then doing the next reasonable thing… repeatedly… for two years.

You start with a product structure that fits a world where you can store something on a shelf, put it in a box, and ship it to a customer. When the business decides to stock other stuff, you add more attributes to accommodate. When the business wants customization — engraving, embroidery, monogramming — and now "the product" has options that change price and lead time, you start sub-typing. When subscriptions, warranties, DRM, and other non-physical entitlements become strategic, you do more of the same. Nothing here is exotic. It's just what happens when the business grows and adapts.

Folding in Traceability

· 4 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 9

In enterprise commerce, totals don't drift because someone forgot algebra. They drift because reality changes: promos expire, eligibility changes when an address arrives, catalog data updates, substitutions happen, and returns unwind prior discounts. When someone asks "why did the total change?" you need more than narration. You need evidence — a trail of facts you can replay and a pure computation that deterministically produces the same result.

That responsibility falls to foldLeft.

Not All Errors are Exceptional

· 6 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 8

Not every "error" in a system represents a defect. Many outcomes that matter to a business are perfectly legitimate: a promotion does not apply, a configuration is incomplete, a shipment cannot be routed to a destination, a request is valid but cannot yet be satisfied. Treating these outcomes as exceptions often obscures their meaning. Exceptions are excellent for broken invariants and infrastructure failures; they are much less effective for representing business decisions that the system should be able to explain, persist, and reason about later.

In Scala, one of the tools commonly used to model these outcomes is Either. There is no shortage of articles explaining how to use Either for error handling, and many of them are worth reading. What those articles sometimes struggle to convey is why this representation changes how systems behave, especially for developers coming from imperative backgrounds. Either can feel abstract until it is attached to a boundary where the distinction between two outcomes actually carries meaning.

Modeling Absence without Ambiguity

· 5 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 7

Most enterprise systems operate under a subtle assumption that proves surprisingly costly: representing absence as a value. In Java and comparable languages, this value is null, appearing everywhere to denote missing, unknown, inapplicable, or forgotten things. Teams eventually stop noticing it, but this familiarity creates problems.

While null wasn't inherently flawed — it solved a genuine constraint in early object-oriented languages — trouble emerged when it began representing multiple distinct concepts simultaneously. In real systems, null might signify that a value doesn't apply, wasn't provided, hasn't loaded yet, a lookup failed, configuration is missing, or upstream errors occurred. All these situations collapse into one representation with no explanation.

Why Pattern Matching Matters

· 6 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 6

By this point in the series, we've spent a lot of time making the mechanics of code disappear. We stopped mutating values because mutable values drift. We stopped depending on external state because it breaks determinism. We stopped writing statements because expressions are clearer, safer, and easier to compose. And, most recently, we stopped writing loops because functional transformations let the business logic stand on its own.

But there is another way imperative languages obscure meaning — and this one is subtler. It happens any time a developer tries to figure out what kind of thing something is before deciding what to do with it.

Beyond the For-Loop: Mastering map, filter, and flatMap

· 5 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 5

Even after developers embrace immutability and pure functions, one imperative construct persists: the for-loop. It remains the last artifact to disappear because it's the first structure we learn. In Java, it feels inevitable as the only intuitive way to examine lists, select relevant data, and produce results.

However, for-loops obscure business logic. Before expressing a domain rule, developers must decide how to iterate, where to accumulate results, when to branch, which state to mutate, and how structures evolve. All of that precedes stating anything meaningful about the business itself.

Thinking in Expressions, Not Statements

· 4 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 4

Developers transitioning from non-functional languages typically acquire functional concepts incrementally — lambdas, immutability, pattern matching, collection operations. While the syntax may appear elegant, the fundamental conceptual breakthrough often comes much later. That breakthrough involves recognizing that thinking in expressions rather than statements represents the true bridge between imperative and functional paradigms.

Imperative programming emphasizes procedural steps with variable mutation. Functional programming reframes the question entirely: "What value are we computing?" This expression-centric approach eliminates entire classes of complexity because there's no timeline of state changes, no mutable accumulators, and no branches requiring variable adjustments. Everything becomes composable values.

Pure Functions: Your First Step Toward Bug-Free Concurrency

· 9 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 3

In Part 2, we explored how mutable state — especially state that someone once believed was a fact — tends to drift over time, and how this drift destabilizes large systems. Immutability is a corrective measure: if something is a fact, preserve it. But immutability addresses only one dimension of stability. The other dimension concerns the way behavior is expressed — whether the logic we rely on actually does what its name claims, or whether it also does several other things we never quite account for.

When developers talk about pure functions, they often recite the textbook definition: same inputs, same outputs, no side effects. It's correct, but it undersells the point. Purity is not an aesthetic choice or an academic curiosity. It is a way of reclaiming control over the semantics of your system. It is how you establish that a piece of business logic actually behaves like business logic, rather than a negotiation with global state, shared caches, volatile time checks, and whichever service instance happens to answer the call.

Immutability by Default: The Foundation of Reliable Systems

· 9 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

Functional Programming Isn't Just for Academics — Part 2

Most introductions to immutability begin with trivial examples. A string is mutated, the result changes, and we are invited to contemplate the danger. But enterprise systems don't fail because someone appended characters to the wrong buffer. They fail because something that was supposed to be a fact — a value that anchored downstream behavior — continued to evolve with the system rather than remaining bound to the moment it was created.

Distributed systems fail when truth drifts. This is why immutability is not a stylistic preference or a functional-programming curiosity. It is the architectural foundation for building systems that behave predictably in a world that does not.

Functional Programming Isn't Just for Academics: Why It Matters for the Systems We Build Now

· 8 min read
Tony Moores
Founder & Principal Consultant, TJM Solutions

In 1983 I asked my parents for an Atari for Christmas, instead I got a Commodore 64… Needless to say, I was very disappointed until I discovered how much cooler Wizard of Wor was than Combat. To their credit, my parents thought a computer was a better investment than a video game. I used that C64 through my sophomore year of college until I replaced it with a 486; my first real investment. So, like many in my generation, I cut my teeth on programming languages like BASIC and LOGO without really picking them for any reason. It was just kind of cool, as a kid, to be able to tell a computer what to do and watch it do it. I quickly understood that animating ASCII stick figures was a BASIC problem and digital Spirograph was a job for the LOGO turtle. In college I was using FORTran for math and science and C for everything else knowing that, depending on the task, one was more natural than the other.