Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
163756 stories
·
33 followers

8 examples of Gemini 4 Argon in action

1 Share
From deep research to interactive design, here are eight examples of what Gemini 4 Argon, our most intelligent model yet, is capable of.
Read the whole story
alvinashcraft
57 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

We’ve had touchscreen laptops for years. Can Apple make them better?

1 Share
Apple MacBook Pro 16 2023
Seeing the light on touchscreen laptops. | Photo by Amelia Holowaty Krales / The Verge

A fridge is about to be merged with a toaster. Dogs and cats are soon to be living together. But it's not mass hysteria; Apple is expected to finally announce a touchscreen MacBook tomorrow at its "Pro and Tell" event.

A laptop with a touchscreen should be no big deal - we've had them for ages. But Apple took a hardline stance against them. In addition to Tim Cook's infamous 2012 quote equating it to combining kitchen appliances, Steve Jobs emphatically dismissed touchscreen laptops as "ergonomically terrible" back in 2010, saying, "Touch surfaces don't want to be vertical."

The closest Apple got was the MacBook Pro Touch Bar, from 2016 t …

Read the full story at The Verge.

Read the whole story
alvinashcraft
57 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Fitbit Edge: Premium design for an active life

1 Share
With a reimagined screen, refined mechanics, and elevated style, Fitbit Edge looks as good as it performs, year after year.
Read the whole story
alvinashcraft
58 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

The platform approach to becoming Frontier

1 Share

Last year at Ignite, we introduced the concept of Frontier Transformation and how it is different from any technology-led pursuit, because it requires us to focus on business outcomes first. It starts with a simple idea: technology was invented to serve humanity, not the other way around. There is no path where this notion of infinite cognitive compute replaces human purpose. Frontier Transformation is an opportunity for a wholesale reinvention of how you think about your unique ideas coming to life and how your organization can thrive in your industry.

Over the course of this past year, we have been leading our customers to focus on the three durable traits that are required for successful transformation: human ambition, intelligence and trust. We are taking a platform approach toward enabling the same: Copilot as the place to call home for interacting with AI to empower human ambition; the Microsoft IQ platform to compound and amplify your intelligence from within while protecting your unique differentiation; and Agent 365 to enable Trust and Observability at every layer of the stack so that you can govern, manage, secure and get business value and return out of the capabilities you deliver.

Our latest earnings are another important marker on that journey. Behind the numbers are thousands of customers, partners, developers and employees putting AI to work in meaningful ways. We have so many inspiring stories from our customers that highlight these outcomes, and below are some of our favorites.

Quote from Judson Althoff, CEO of Microsoft Commercial Business: “Technology was invented to serve humanity, not the other way around. There’s no path where somehow this notion of infinite cognitive compute replaces human purpose.”

Empowering human ambition with Copilot

Volkswagen has scaled Microsoft Copilot to more than 330,000 employees as it expands the role of AI in decision-making and knowledge-based processes across the enterprise. Building on Copilot Chat adoption that reached more than 300,000 monthly active users, employees are now using Copilot with Work IQ for more advanced scenarios, bringing greater organizational context to decision-making and knowledge-based work. Volkswagen is also working with Microsoft to further scale its Intelligent Data Foundation on Microsoft Fabric to make data easier to find, understand and use across the entire company. With this investment, Volkswagen is demonstrating how companies have evolved from using Copilot as a productivity tool to an operating system to empower human ambition.

Following a successful pilot, Fujitsu is scaling Microsoft Copilot across its global workforce of approximately 100,000. Copilot usage has surpassed 90%, and the company is using the tool to connect employees with specialized agents and business systems. AI agents are already automating roughly 75% of initial responses and triage for a service desk that receives nearly 300,000 inquiries annually, while new agents are supporting work across sales, systems engineering, procurement, finance and accounting. As customer zero, Fujitsu is using Copilot as the front door to a multi-agent work environment and using insights from its own AI adoption to better serve its customers.

KOHLER is using GitHub Copilot to transform software development, with one organization improving code releases by 25% and reducing error defects by 75%. These engineering breakthroughs are part of a broader effort to embed AI processes across the company, spanning IT, finance, marketing, supply chain and operations. Microsoft Copilot has reached 98% adoption, saving an average of 2 to 5 hours per month as employees are making informed decisions and getting answers faster in the flow of their work. Employees across the company have also created more than 3,000 agents to date, with hundreds active daily.

At Krafton, Microsoft Security Copilot and Microsoft Defender XDR are helping the security team respond to a growing volume and complexity of threats. The global gaming company automated key parts of security operations, from alerting and investigation to reporting, combining Microsoft Security solutions with its own systems and data to quickly gather context that helps distinguish real threats from false positives. This approach is having immediate results: security alert recognition time has fallen by approximately 95% to less than one minute, investigation work that previously took tens of minutes now takes about three minutes and roughly 95% of report creation has been automated. By taking on repetitive work, AI is giving Krafton’s security professionals more time to focus on responding to real threats and making critical security decisions.

To accelerate discovery across decades of scientific data, NASA is making complex information easier to explore through Microsoft Copilot. NASA employees are using Copilot to sift through massive amounts of academic literature and streamline daily tasks, and specialized assistants are helping researchers navigate complex Earth science data through natural language, extending access to information that once required significant technical expertise. Hydrology Copilot, for example, can analyze variables like precipitation and soil moisture to help communities better understand water conditions, prepare for droughts and anticipate flood risks, while automatically performing calculations and analyses.

To transform frontline work, Williams, a US natural gas company, is using Microsoft Copilot to help employees spend less time searching documents and completing manual processes, and more time on critical field operations. Copilot helps teams generate plans, interpret procedures, assess regulatory requirements, troubleshoot issues and complete safety reporting, while employees can create agents tailored to their own workflows. Demonstrating that the person closest to a problem is often the best one to solve it, one operations technician built an anomaly detector using Copilot that compares equipment data against baseline statistics and alerts teams to potential issues before they become costly or dangerous. Since deploying Copilot, AI adoption at Williams has grown from single digits to more than 90%, helping employees accelerate operations, improve reporting and compliance and identify equipment issues earlier.

Bristol Myers Squibb has rolled out Microsoft Copilot to 25,000 employees, reaching 96% adoption, and is now putting AI agents to work across everyday use cases such as document review and project management in support of the company’s mission to bring more medicines to more patients faster. One agent, called RABIT, analyzes meeting transcripts, surfaces action items and delivers insights directly within employees’ workflows.

Facing rising patient demand and financial pressures, Brown University Health is using Dragon Copilot to give clinicians more time to focus on patients. The health system adopted Dragon Copilot, and an early pilot across 420 clinicians found users spent less time on after-hours documentation and reported lower cognitive burden. Building on that experience, Brown University Health deployed Microsoft Copilot and Copilot Studio across departments, which led to the creation of more than 24 AI agents to support clinical workflows, hospital policies, patient access and operations. These AI solutions are not only supporting clinicians in the flow of their work but also helping to improve the patient experience and access to care.

Microsoft IQ compounds and protects your intelligence

BNY has made AI part of how its employees work through Eliza, its in-house AI platform built with Microsoft Azure, Microsoft Foundry, Microsoft Copilot and GitHub Copilot – with plans to add Work IQ. More than 300 solutions now run on Eliza, ranging from inquiry management to client onboarding, and 100% of employees have been trained on the platform. Across the bank, that scale is translating into meaningful results: client transaction inquiries are being resolved 80% faster and AI-assisted client onboarding is 20% faster on average. Through the Microsoft CEO Co-Innovation program, BNY also worked with Microsoft to develop an AI research capability with Foundry that investigates complex data issues, analyzes context across multiple sources, identifies likely root causes and recommends next steps, bringing AI-assisted reasoning into processes that have traditionally relied on human investigation alone.

Docusign is helping 1.9 million customers across 180 countries turn agreement data into actionable business insights. The company built an Intelligent Agreement Management platform on Microsoft Azure and used Microsoft Foundry to shift from general-purpose models to a system of task-specific models that better understand context. This change allows Docusign to process more than a million agreement documents daily with up to eightfold greater throughput and 90% lower AI processing costs. Foundry also supports a model lifecycle designed for continuous improvement, where processes are fine-tuned before deployment and monitored in production, while also providing the governance and traceability needed to meet enterprise requirements for compliance, visibility and control. Now agreement content is structured data that compounds from within, so organizations can use it to make decisions and automate workflows, knowing their IP is protected.

To help marketers create more effective content, Kantar turned decades of proprietary advertising intelligence into action with Microsoft Azure and Microsoft Foundry. Working with Microsoft Frontier Company, Kantar connected its LINK AI platform to its proprietary intelligence, AI models and creative workflows, enabling marketers to evaluate, optimize and generate content before it goes to market. The new approach can process and score large volumes of videos 20x faster while reducing platform operating costs by 4x, helping customers move from insight to action in minutes rather than hours. By bringing its unique intelligence into a continuous loop of observation and improvement, Kantar is creating new ways to help marketers turn insight into better creative and business outcomes.

Kinaxis, a Canadian supply chain software company, runs Maestro, its AI-driven supply chain orchestration platform, on Microsoft Azure. Maestro helps businesses make better decisions faster amid constant disruption. It brings together traditionally disparate business data like sales orders, inventory and production capacity with external signals like weather, market shifts and breaking news to give planners a near real-time view of their supply chains. With this unified data foundation, planners and analysts can use predictive AI and optimization models to anticipate demand shifts, evaluate constraints and recommend action, while generative AI agents act as assistants to ask questions, explore scenarios and automate parts of the planning process. With this intelligence in one platform, businesses can understand how disruptions ripple across their interconnected operations, weigh trade-offs and adjust plans as conditions change.

Moody’s is making more than a century of credit and risk intelligence directly accessible through Microsoft Copilot, giving customers trusted, protected context for complex decisions. Through a federated connector built using Model Context Protocol, customers can access live, decision-grade Moody’s intelligence through Researcher in Copilot and within Word, Excel and Teams, without copying or exporting the underlying data. A single question can synthesize information across credit ratings, company financials, ownership information and physical risk models, helping customers reach insights in minutes instead of spending hours or days on research and analysis. This brings trusted, connected intelligence directly into workflows where customers make complex decisions.

To turn conversations into actionable intelligence at global scale, Plaud, an AI hardware and software company, is using Microsoft Azure OpenAI in Foundry Models and Azure Speech in Foundry Tools to power transcription, summarization and AI inference across long-form audio and multilingual scenarios. Serving more than 2 million users worldwide, Plaud increased transcription accuracy and processing speed by 35% and improved inference performance by 30%, helping professionals turn spoken content into structured outputs and insights. Even as its user base doubled, the company used Foundry’s elastic scaling and flexible deployment models to reduce overall compute costs by 35%, while strengthening its ability to meet security, privacy and compliance requirements across global markets.

Rockwell Automation built a Maintenance Copilot using Microsoft Foundry to put decades of manufacturing expertise in the hands of employees. The AI assistant brings together expert knowledge from veteran engineers, manufacturing data and machine manuals, allowing technicians to quickly identify likely causes of equipment issues, see how colleagues have solved similar problems and access step-by-step troubleshooting guidance. At its Singapore factory, the approach has helped reduce machine downtime by 33% and cut servicing and spare-part costs by about 25%. Rockwell estimates it has also reduced the time it takes new workers to learn to troubleshoot hundreds of machines from nine months to three months.

With 1.5 billion passengers riding its elevators and escalators every day, TK Elevator knows that every minute of downtime affects how people move through airports, hospitals and offices. Building on a decade of connected-equipment data on Microsoft Azure, the company created AI agents with Microsoft Foundry that brief service technicians before they enter a building, telling them which elevator, which floor, what the issue is and which tools to bring. After each job, a voice agent records the technician’s account of the work in their own words, with no typing, and adds that expertise to a shared record. With 25,000 technicians caring for 1.4 million units worldwide, TK Elevator is turning each technician’s know-how into compounded intelligence every colleague can draw on.

Telstra partnered with Microsoft Frontier Company to deploy an AI-powered Migration Payment Agent that helps simplify one of the most complex aspects of customer migration: reconciling billing and payments across legacy and new platforms. The agent uses intelligence across these systems to proactively identify inconsistencies, recommend corrective actions and create enriched cases for human review, combining AI-driven insights with human-in-the-loop validation to maintain operational trust and governance. Already supporting more than 272,000 service migrations and delivering recommendations at 95%+ accuracy in production, the solution demonstrates how Telstra is applying agentic AI at enterprise scale to transform complex operations, improve customer outcomes and build reusable AI capabilities while compounding and protecting Telstra’s operational intelligence.

Agent 365 observes AI solutions across the stack

To advance its transformation into an AI-powered organization, Manulife is adopting Microsoft 365 E7: The Frontier Suite, expanding Microsoft Copilot to more than 30,000 employees and leveraging Microsoft Agent 365 to govern, manage and secure AI agents at enterprise scale. With Microsoft Azure and Microsoft Foundry supporting its global enterprise AI platform, Manulife is building a foundation for teams to develop and deploy AI and agentic solutions while maintaining standards for quality, security and cost efficiency. AI is already delivering impact across the business, from generative AI solutions supporting more than 110 million customer calls annually to developers increasing productivity by 30% with assisted and autonomous AI capabilities. With agentic solutions and AI-powered workflows already in production, Manulife is creating the foundation to scale AI responsibly across its global operations and accelerate its next phase of enterprise transformation.

Insight Enterprises, a leading solutions integrator and top Microsoft partner, is using Microsoft Agent 365 to govern AI agents at scale. As a Microsoft customer zero organization for Agent 365, Insight Enterprises is quick to adopt new capabilities internally and pass those learnings on to clients. With Microsoft engineering, it tested how Microsoft and third-party agents could be observed, managed, governed and secured through a unified control plane. To date, Insight Enterprises has discovered 9,734 agents with visibility into which are active, what data they can access and how to monitor their activity over time. The experience has helped Insight Enterprises build practical AI governance expertise it can bring to customers, including organizations in highly regulated industries.

KPMG is adopting Microsoft Agent 365 to manage and secure AI agents across its global organization, providing centralized observability and control as it scales agentic AI. Agent 365 will also strengthen KPMG Workbench, its multi-agent platform built on Microsoft Foundry that coordinates agents across client service delivery platforms. At the same time, KPMG is expanding Microsoft Copilot to more than 276,000 professionals worldwide, helping embed AI more deeply across audit, tax and advisory services. Together, these capabilities are giving KPMG the confidence and security to move agents from experimentation into enterprise-wide deployment, while helping clients do the same.

Operating in one of the most highly regulated industries, where protecting sensitive customer information is essential, Truist Financial Corporation is using Agent 365 to manage, govern and observe more than 13,000 AI declarative agents across its organization. Truist manages its agent ecosystem with discipline: every agent has an accountable owner and agents are automatically disabled after 45 days of inactivity. That rigor is driving strong retention and adoption, with more than 8,000 agents active each month. Building on this trusted foundation, Truist has advanced its broader AI strategy through their investment of more than 50,000 Microsoft 365 E7: The Frontier Suite seats.

—

Every quarter gives us an opportunity to step back and look at the progress we are making with our customers and partners around the world. What continues to strike me is not simply the pace of change, but the ambition we see from organizations using technology to achieve aspirations that simply weren’t possible before. We look forward to working alongside you on the path to becoming Frontier, and we hope to see many of you at Microsoft Ignite this year in November to share the latest innovations that will enable you to reach that destination.

Judson Althoff is the chief executive officer of the commercial business at Microsoft. He is responsible for the product strategy, sales, services, support, marketing, operations and revenue growth of the company’s commercial business, which operates in more than 120 regional and national subsidiaries globally.

The post The platform approach to becoming Frontier appeared first on The Official Microsoft Blog.

Read the whole story
alvinashcraft
58 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Two years later, I know what I got wrong about typed domain errors and what I’d keep

1 Share

I love this style: a function’s expected failures are spelled out in its signature as a sealed type, rather than hidden in its body.

A couple of years ago, I tried something very similar in a toy project, but I never saw the contract benefit. The style wasn’t the problem, and doing more of it wasn’t the fix.

This essay responds to a JetBrains blog post about typed domain errors. I agree with its diagnosis, though I’m clearer about what not to do than about the ideal approach. I also share what I got wrong, in the hope you can avoid the same mistakes.

The blog post I’m responding to

Sergey Chernov’s “Signatures, be true: domain errors and functional handling in Kotlin” makes a claim I strongly agree with: a signature like fun signDocument(id, code): Unit that throws in secret is lying about what it can do, and the fix is to put the expected failures in the type.

His core contribution is the three-category taxonomy, and it’s the most useful part of the post.

  1. API client misuse, e.g. malformed JSON, a missing header or an out-of-sequence request. Collapse these to a coarse 4xx and keep them out of the domain model. Access control is a partial exception. A bare authentication failure is transport-level and stays out, but an ownership or permission decision that depends on business state often belongs in the union, because the caller needs the specific reason and not just a 403.
  2. Unexpected exceptions, e.g. the database being down, a timeout, a dropped network or a bug. Throw these, and let the global handler turn them into a 500 with a stack trace and an on-call page.
  3. Domain errors, e.g. a wrong sign code, a closed window or an already-signed document. This is the only category that belongs in the contract, as a sealed type.

A sealed type, in case that term is unfamiliar, is a closed hierarchy where the compiler knows every subtype. That is what makes a when over it exhaustive, with no else branch, and it’s the whole game.

Everything else in the post is implementation. It covers a sealed interface for the error union, an Either<DomainError, T> return, exhaustive when, HTTP mapping only at the route boundary (the Ktor layer that owns the routes). It also publishes the error types alongside the API client, and its central recommendation is one narrow union per public method, rather than one shared union across a class. Here Either is just a value that is either a Left failure or a Right success. The line I would keep is “the contract is the unit of review”, which means you read the types rather than the 200 lines underneath. That is doubly true when an AI wrote the implementation.

The post also skips over how to compose heterogeneous error unions, which is real work I had to figure out on my own. Real flows fail per step with different unions. A plain either { } block, which chains fallible steps and short-circuits on the first failure, infers a single left type from all of them. Mixing unrelated domain errors therefore gives you their least upper bound, meaning the most specific common supertype the compiler can find. When the types are unrelated, that is Any, which is the open-error problem the post warns about. A shared sealed interface is different, since it stays closed, but a union that broad is the contract bloat the post warns about elsewhere.

The post is also quiet about how to observe legitimate domain values. It says even less about the cost of mis-categorizing infrastructure failures as domain errors, which I ran into myself. The same open-type reasoning is why Result<T> is a poor fit for domain modeling. Its failure side is Throwable, so a when over the failure value always needs an else and the contract gains nothing.

A note on the boundary: API-client misuse vs validation

One line the taxonomy leaves murky is the line between API client misuse and validation. I read that line as two different things the post merges.

The first is structural or transport validation, such as malformed JSON, a missing field or a wrong wire type. This is genuine client misuse. A healthy client never produces it and no designed screen is needed, so a coarse 400 is enough.

The second is semantic validation, where a well-formed field violates a real rule and carries a meaningful message, like TooShortUsername or NoDigitsInPassword. Here the client benefits from knowing exactly which field is wrong and why, and often from getting all of the problems at once rather than just the first one.

Where the exact line falls is not well-defined, as it depends on the use case and on the implementor’s preference. Some APIs deliberately collapse semantic validation to a coarse 400. Others return rich, accumulated field errors, which is what my validation tree did and it’s the part I still like. My own leaning is to let structural junk stay a coarse 400 at the framework boundary. Semantic validation can come back as a value, accumulated, but kept as its own validation-result type rather than folded into the business domain union.

One wrinkle deserves naming. A rule like “this email is already taken” looks like validation, but it reads persisted state, so it’s really a domain conflict and belongs in the domain union, not in the request-validation result. It’s a fair criticism of the taxonomy that the first category needs this much boundary work, but it’s still a better starting point than nothing. I won’t pretend there is a single correct division here. It’s a judgment call for each API.

My case study: a good design at the wrong layer

In 2024 I built a Ktor/Kotlin/Arrow backend (instakt, now an unmaintained toy project) and went fully functional on error handling, but with no grouping by use case. This is how the style gets misused, and the taxonomy above is the frame I wish I had back then, because without it I mislabeled infrastructure failures as domain outcomes.

The design was coherent in principle. One wide root union DomainError held a large tree of cases, and my database bucket alone had about 26 of them. Services mostly returned EitherNel<DomainError, T>, though a few methods returned a non-accumulating Either<DomainError, T> instead. EitherNel is an Either whose failure side is a NonEmptyList, which is how several errors get accumulated.

A single total mapper DomainError -> HttpStatusCode owned all of the exhaustiveness. It handled every case and returned a status, while the response body carried the error detail. It looked elegant and it compiled. Reading it back, three things were wrong.

The most obvious problem was that the per-method contract was gone. Every method returned the whole DomainError union. A signature like upload(...): EitherNel<DomainError, ContentMetadata> told a reader almost nothing about which failures that one call could produce. The blog’s whole point, that the signature tells you what can go wrong for this call, was silently surrendered. Because the central mapper owned exhaustiveness, I avoided the impossible-branch work, but the signature stopped telling the truth.

The problem I most regret was observability. I had modeled infrastructure failures, a failed persist or a failed mail send, as union values. My exception<Throwable> handler logged only cause.message with no stack trace. Between the two, infrastructure failures were turned into a status by the mapper and never reached the global handler at all. That meant no log entry, no trace and no error-rate spike, which is exactly why the blog says unexpected exceptions should throw. Grouping errors by use case would not have fixed this, and I want to be explicit about that. It was a separate mistake that needs a separate fix.

The last problem was bloat. A shared root collects one more case from every operation, so there was no natural place to stop. Discovery got worse too, because every new failure landed next to unrelated ones.

What was actually good: validation

The part that aged best is validation, and that’s not a coincidence. Validation is the one concern where the design matched the shape of the problem. A form wants all of its errors at once rather than the first one, so the accumulating checks served a genuine UX need. Nowhere else in the project was accumulation load-bearing. Field validation is also the purest domain concern, because it judges the request itself and never needs the database, storage or infrastructure.

The nested tree earns itself here too, since field-level messages and group-level routing are two different consumers of the same structure. Each check is also a self-describing type such as ContentSizeIsValid, so a failure names exactly what was checked, even if the surrounding method signatures were still too wide to be useful.

The lesson I draw is that error handling works best when it’s shaped by the operation’s structure. In my experience independent checks want to aggregate, while sequential business steps want to short-circuit or narrow per use case. Validation happened to be the only thing that was structurally an aggregate problem, so it came out right almost by accident. Aggregate independent checks (like validation); short-circuit sequential business steps with a narrow, use-case-specific outcome. Validation happened to be the only thing that was structurally an aggregation problem, so it came out right almost by accident.

What I’d try next

I haven’t tested these in production, so treat them as hypotheses, not a proven design. The change I’d make first is to group by use case. By use case I mean the operation the caller asked for, not the function that happens to serve it. Uploading a profile photo and deleting a document are different use cases even when they share the same repository, and each one gets its own closed union of the failures it can produce. The wide union then lives only at the transport layer, where a single mapper to HTTP status genuinely belongs.

That leaves the composition question. A narrow service union widens into the transport union through a small total mapping at the boundary, and that mapping is where the composition happens. One function there turns each UploadError into the matching case of the wide union, as in UploadError -> DomainError, while the signature itself stays narrow, something like fun upload(...): UploadError. When a flow runs several steps, its union collects the cases those steps can produce that the caller must distinguish. That mapping is total, so adding a case stops the boundary compiling until it is handled, and it works the same whether the result is wrapped in an Either or a hand-written outcome type. It is deliberate and named, which separates it from the inferred collapse I described earlier, and it is acceptable only because the broad union never reaches a service signature. The cost is more up-front ceremony, a set of small types and a mapping per use case, but I think it’s worth it because the contract becomes readable, and I’d keep each mapping next to the type it converts so a new case stays a local edit.

For the result type, I now prefer plain when plus hand-written per-use-case outcome types over Either. I tried Either, and while it reads fine, the machinery around it wears on me. The cost is the Arrow either { } builder plus the chained calls that unwrap a success or short-circuit on a failure. It is not the Either type itself, which is a small sealed pair. As the years pass I’ve come to prefer the simplicity of a when and a set of small named types. This is a matter of taste, but it’s where I lean today. I’d also match the mechanism to the shape of the work. In my experience validation wants to accumulate, while a business flow wants to short-circuit through a narrow outcome type. I see no reason to force one mechanism everywhere.

Observability needs its own attention, and it matters more in this style, not less. Going from exceptions to domain errors means you lose the stack trace unless you deliberately keep it. So I’d log expected domain failures at info or debug with a correlation ID. The global handler would keep the error-level logging for thrown exceptions, so nothing gets logged twice. I’d still throw for genuine unexpected exceptions, the ones that cannot be categorized as domain or client. The rule I hold myself to is to build domain errors from data I already have and never wrap raw database or network failures into the union. That rule is still coarse. A bounced email is a domain outcome, while an unreachable mail server is not. The real test is whether a correct client could still hit the failure and act on it.

Narrow unions are also self-documenting in a way a wide one is not. A signature that returns a narrow, per-use-case error type tells a reader what can fail, while one that returns DomainError tells them almost nothing. For context, an early proposal in the Kotlin Evolution and Enhancement Process, KEEP-0441 “Rich Errors, aka Error Union Types”, would add error-union types to the language. It’s still at the design review stage, so it isn’t accepted or promised, and it isn’t an Arrow-specific idea. The error contract also has to survive releases. The concrete hazard is that adding a case to a shared sealed type is a breaking change for every client whose when is exhaustive. It also breaks serialization when an unknown case arrives from a newer producer. I’d treat an unknown incoming case as a defined fallback rather than a crash. This matters far less when the consumers are ours to rebuild in lockstep, as with internal models, and much more when a customer-facing connector is involved.

On conventions I don’t think there is one right answer, since it always depends on the use case. I like names that are clear and descriptive. I’d use a data class whenever an error carries data, and object or data object when it does not. A data object needs Kotlin 1.9 or later, and a data class requires at least one property. I lean toward carrying data where I can, because an error that carries a payload is easier to debug and test than one that carries nothing. For nesting, validation seems to benefit from it, while in general I’d strive for flat, per-use-case errors, though there’s no universal rule and it has to be tested in context. Testing gets easier too, because you assert on the returned error value directly instead of catching a thrown type.

Where I land

I still reach for this style, only with clearer boundaries. The blog’s taxonomy and its “contract is the unit of review” idea are worth keeping. Its flat “one narrow union per method” advice is a reasonable default at the level of the operation, though not for every helper function. A wide union with a central mapper still has a home at the transport layer.

The honest summary of my two years is that a coherent wide-union pipeline is a defensible transport design, but it was the wrong layer for it. I can’t promise the approach I’d try next is the right architecture either, because I haven’t built it yet. What I’m confident about is the failure mode. My first attempt taught me that the hard way, and I hope it saves you the tuition.

The post Two years later, I know what I got wrong about typed domain errors and what I’d keep appeared first on ShiftMag.

Read the whole story
alvinashcraft
59 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Apple introduces the new 14-inch MacBook Pro with M6

1 Share
Apple today announced the new 14-inch MacBook Pro with M6, delivering more performance, powerful on-device AI capabilities, and faster connectivity.

Read the whole story
alvinashcraft
59 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories