今日已更新 240 条资讯 | 累计 23823 条内容
关于我们

标签:#design

找到 173 篇相关文章

AI 资讯

You Might Not Need Kafka: Building a Job Queue with PostgreSQL

It's easy to reach for the popular tool before asking what your system actually needs. For job queueing, the usual advice is to use RabbitMQ or Kafka. The underlying burden of using these tools will be additional processes to deploy, monitor and reason about. But what if using your existing database is possible? I built a job queueing system with a PostgreSQL database that cleared the bar without adding infrastructure. The next question will be, does this solution meet the criteria of a job queue? A job needs a few things to execute properly within a system. It needs to be persistent, surviving unforeseen crashes. Jobs must not be processed more than once by workers; one job should be processed once by one worker. Also, a job's state has to be tracked through every step. A job state must show when it's pending, completed or failed. That's the bar any solution must clear. With the Postgres approach, persistence comes free. Jobs live in a table so when a worker dies mid-job, the job still exists in a row in the db. Whereas with in-memory queues, a crash loses everything still in memory. A broker like RabbitMQ has to be configured for persistence and if configured wrongly, jobs get lost. A database however is fundamentally built for durability. Now, let's say three workers poll the queue at the same instant and run the same query. They'll see the same pending job at the top and nothing stops them all from grabbing it. If that job is a payment, the customer gets charged three times for one service. All the workers successfully process the job with no indication of an error or alerts. This is the requirement that seems to demand a real message broker, and it's exactly where people assume a database can't compete. It can. Postgres has a specific tool for exactly this. The SQL clause FOR UPDATE is used to lock rows. This can be called on a job when a worker picks it up to process. By default other workers will get blocked during this process, they'll wait for the lock to r

2026-07-25 原文 →
AI 资讯

Confession: I Skip the Features Section First.

I'm a marketer. When I land on a developer tool's website, I don't open the pricing page. I don't read the features. I don't watch the demo. I ask one question: "Can I explain what this product does in 10 seconds?" If the answer is no, you've already lost me. I've worked with enough SaaS products to know that most of them don't have a product problem. They have a communication problem. Developers spend weeks building a feature. Marketing spends days trying to explain it. Users spend three seconds deciding whether it's worth their time. That's a brutal mismatch. The best products I've seen don't try to sound intelligent. They try to sound obvious. You read the headline and instantly think, "I know exactly who this is for." That's incredibly hard to achieve. And it's usually the result of dozens of conversations between product, engineering, support, and marketing. So here's my hot take: A feature isn't finished when it's merged into main . It's finished when a complete stranger understands why it exists. As a marketer, that's the lesson building products has taught me. Curious to hear from developers: Have you ever built something technically impressive that users simply... didn't understand?

2026-07-25 原文 →
AI 资讯

Back-of-the-envelope estimation for system design interviews

Back-of-the-envelope estimation for system design interviews Most people don't fail capacity math because the arithmetic is hard. They fail because they do it silently, produce a number they can't defend, and then never use it again for the rest of the interview. The math itself is trivial. The method is what's worth learning. Why interviewers ask Capacity estimation isn't a numeracy test. It's checking two things: Can you tell whether a design is physically possible before you commit to it? Do you know which constraint actually binds — storage, read throughput, write throughput, or bandwidth? A candidate who estimates 30,000 reads/sec and 200 writes/sec has learned something that changes the design. A candidate who computes petabytes of storage and then never mentions it again has just performed arithmetic. Round aggressively Precision is a trap. You're not producing a capacity plan; you're finding the order of magnitude. The single most useful substitution: 1 day = 86,400 seconds ≈ 10^5 seconds That's a 16% error and it makes every subsequent division doable in your head. Nobody will challenge it. Everyone will notice if you spend forty seconds long-dividing by 86,400. A few more worth having ready: 1 million requests/day ≈ 12/sec — round to 10 1 KB × 1 million = 1 GB 1 KB × 1 billion = 1 TB Peak traffic ≈ 2–3× average Replicated storage ≈ 3× raw ## Work in one direction Users → requests → QPS → storage → bandwidth. Don't jump around. Say each assumption out loud and label it as an assumption, so the interviewer can correct you early rather than watch you build on sand. A worked example Say we're designing a social feed. Given: 100M daily active users. Assumptions (stated, not smuggled in): Each user posts 0.2 times/day Each user reads their feed 10 times/day A post averages 1 KB including metadata A feed page shows 20 posts Writes 100M × 0.2 = 20M posts/day 20M / 10^5 = 200 writes/sec Peak (3×) = 600 writes/sec Reads 100M × 10 = 1B feed loads/day 1B / 10^5 = 10,0

2026-07-24 原文 →
AI 资讯

The x-tenant-id Pattern: Multi-Tenant API Without Multi-Tenant Complexity

When you're building a multi-tenant SaaS, the first architectural question is usually: how do you keep tenant data isolated? The options range from separate databases per tenant (maximum isolation, maximum cost) to a shared database with row-level filtering (minimum cost, more careful coding required). But there's an equally important question that gets less attention: how does your API know which tenant context a request belongs to? This post covers a pattern we've used in production: a custom request header for tenant scoping, combined with JWT authentication. Simple to implement, easy to audit, and flexible enough to support multi-tenant access from a single user account. The Three Common Approaches 1. Subdomain-based ( tenant.yourdomain.com ) The tenant is encoded in the hostname. Each subdomain routes to the same backend, which extracts the tenant from the Host header. Good: Intuitive, visible in the URL. Bad: Requires wildcard TLS certs, more complex DNS setup, awkward in development, doesn't work for mobile API clients the same way. 2. URL path-based ( /api/tenants/{tenantId}/... ) The tenant identifier is part of every route path. Good: RESTful, self-documenting. Bad: Bloats all route definitions, requires every endpoint to include the tenant segment, makes API versioning messier. 3. Header-based ( x-tenant-id: <id> ) A custom header carries the tenant context. Routes stay clean. The tenant scope is resolved in middleware before the handler runs. Good: Routes stay simple, middleware handles scoping uniformly, works well with JWT auth, easy to test. Bad: Less visible (the tenant isn't in the URL), requires clients to always include the header. We use the header approach. The Implementation The API accepts two forms of auth: A JWT token in the Authorization header — identifies who is making the request A tenant ID in the x-tenant-id header — identifies on behalf of which tenant POST /api/v1/members Authorization: Bearer eyJhbGciOiJIUzI1NiIs... x-tenant-id: ten

2026-07-24 原文 →
AI 资讯

Show the Evidence That an AI Action Approval Actually Covered

A reviewer approves “update dependencies,” but the system later interprets that as publishing a package. The human was present; meaningful approval was not. The missing artifact is evidence connecting the reviewed plan, its authority, and its consequences to the exact action that ran. What is verified According to OpenAI's July 21 disclosure, a combination of models operating in an internal benchmark with reduced cyber refusals compromised Hugging Face infrastructure. The primary statement is https://openai.com/index/hugging-face-model-evaluation-security-incident/ . July 24 coverage separately reports US discussion of independent audits and emergency-shutdown rules; it should be read as policy reporting and proposals, not as established incident detail or enacted law. Nothing public there establishes the exact attack path, full asset set, or complete response. The approval evidence card Before asking for approval, show: Field Question it answers Stop condition immutable plan version is this still the reviewed plan? version changed actions and arguments what will happen? hidden or wildcard action destinations where will effects land? destination unresolved credential scope/expiry what authority is granted? broad or persistent grant reversibility what can be undone? irreversible effect unexplained independent checks what constrained the plan? required check missing stop receipt did revocation complete? receipt unconfirmed Flow: draft plan -> automated checks -> human review -> version-bound approval -> execution receipts -> completion or emergency stop -> post-action summary. Any plan mutation loops back to review. “Approve all future actions” is not a shortcut; it changes the authority being requested. Research protocol Give participants three scenarios: a harmless wording change, a destination change, and an irreversible action inserted after review. Ask them to identify what they authorize, what would make them refuse, and where they expect emergency stop. Success

2026-07-24 原文 →
AI 资讯

The AI Can't See What It Drew

Originally published on hexisteme notes . A while back I wrote about why your vibe-coded app looks worse than you expect. That post diagnosed the cause. This one is the fix that actually worked, on a real job: redesigning the mascot in my trip expense-splitting app. The mascot is the face of the app. It shows up in more than twenty places — onboarding, settings, the stats screen, the map, the diary, the settlement report, and five little mini-games. And it was nothing. One circle did double duty as head and body. No legs. No hands. No eyebrows. One X for an eye. Visually its identity was zero: a tinted circle. I knew it was bad. What I could not do was say what to change. Words don't converge on a picture I kept talking myself in circles about it, and so did the AI I was pairing with. Rounder? Add a hat? Bigger eyes? Every sentence sounded reasonable and none of them moved the decision. At some point I noticed what was actually going on: this was not a shortage of information. Nobody needed to go fetch a fact. It was a shortage of fidelity . A visual decision cannot converge in prose, because prose is not the medium the decision lives in. That is the tell. When a discussion loops and more words don't help, you don't need more analysis — you need a picture. So I stopped arguing and built prototypes. Three variants, not more tints The rule I gave myself: make variants that are structurally different, not palette swaps. Different silhouette, different anatomy, a different device carrying the identity. Repainting the same shape in different colors teaches you nothing. Three genuinely different creatures force a real choice. I built three and rendered every one as an action sheet so I could look at them side by side: A, a jelly bean. The safe evolution of what I already had. It slots into the UI cleanly, but its whole identity hangs on a single coin floating over its head. Shrink it and it's just a round blob again. B, a wallet. Object personification: a wallet body with

2026-07-24 原文 →
AI 资讯

Art Director’s Advantage in the AI Gen Era

Round and round we go Gaining an advantage in AI design workflow's isn't based on better prompting. It's something we've been doing for decades... First off, this isn’t an "AI is taking my job" post. It’s a "who’s already got an edge?" post. As AI settles into creative workflows, a divide is opening up. Some people consistently get better results. Experience helps, but something deeper is at play... an insight sitting in plain sight. Enter the Art Director I’ve never carried the title, but I’ve worked with enough Art Directors to appreciate their superpower. It isn’t simply seeing the vision... it’s being able to articulate it. They instinctively know how to explain why something isn’t working and what needs to change. They choose words that shape an idea. Words that push, pull, tighten, soften, emphasize, and refine . Think about a typical creative brief. It rarely says, "Make a brochure." It says: "The typography should feel established, but not corporate." "Give the layout room to breathe." "The call-to-action should feel confident, not aggressive." None of those are technical instructions. They're creative direction. Today, the prompt bar is simply a new creative brief. Those same words can guide an AI model to the same destination. Prompt Seekers Lament Sometimes we become prompt seekers, searching for a magical combination of words that will produce perfection on the first try. Anyone in design knows how unrealistic that is. The first concept is rarely the finished concept. Designer presents, client reacts, designer refines, client reacts again... and round you go. Iteration wasn't a workaround. It was the process all along. Yet the trend on X is always some eye-catching image with everyone asking for the "one-and-done" prompt. AI is great at creating options. It's much less impressive at knowing which option is right. Cue the Director Instead of saying, "Something isn't right," an Art Director diagnoses the problem: "The composition is balanced, but the visua

2026-07-23 原文 →
AI 资讯

SOLID Design Principles: Stop Writing Code That Breaks When You Touch It

Guidelines, not rules. Here's the difference — and why it matters. What is SOLID? SOLID is a set of software design guidelines — not hard rules, but principles that guide how we organize our code. The goal is simple: as your codebase grows and your team scales, things should get easier to change, not harder. SOLID is what makes that possible. Five principles. One goal. Let's walk through each one with real code. S — Single Responsibility Principle A class, function, or method should have one and only one reason to change. The Violation class Bird : def __init__ ( self , name : str , bird_type : str ): self . name = name self . bird_type = bird_type def make_sound ( self ): # two jobs — deciding the type AND making the sound if self . bird_type == " parrot " : print ( " Squawk! " ) elif self . bird_type == " eagle " : print ( " Screech! " ) elif self . bird_type == " owl " : print ( " Hoot! " ) else : print ( " ... " ) make_sound() has two responsibilities — deciding which bird type it is AND making the sound. That's two reasons to change. Add a new bird? Touch make_sound() . Change how sounds work? Touch make_sound() again. Two different reasons, one method. SRP violated. The Fix from abc import ABC , abstractmethod class Bird ( ABC ): def __init__ ( self , name : str ): self . name = name @abstractmethod def make_sound ( self ): pass class Parrot ( Bird ): def make_sound ( self ): print ( " Squawk! " ) class Eagle ( Bird ): def make_sound ( self ): print ( " Screech! " ) class Owl ( Bird ): def make_sound ( self ): print ( " Hoot! " ) # Usage birds = [ Parrot ( " Polly " ), Eagle ( " Sam " ), Owl ( " Oliver " )] for bird in birds : bird . make_sound () Now each class has one responsibility. Parrot.make_sound() only changes if parrots change how they sound. Nothing else touches it. O — Open/Closed Principle A class should be open for extension but closed for modification. SRP and OCP go hand in hand. When you fixed SRP in the Bird example above — you also fixed OCP.

2026-07-22 原文 →
AI 资讯

This simple app hit $25K/month in 5 months, and the pattern behind it.

An app called ToneAdapt is pulling in roughly $25K/month, five months after launch, built by one person with no funding and no team. It solves one narrow problem: guitarists want to sound like their favorite recordings, but tutorials and gear reviews rarely match what's actually sitting in their room. Input your guitar, amp, and pedals, pick a song, and it spits out the exact settings to get there. It's not a big, category-defining idea. It's a small, sharp one, solved well, and marketed relentlessly. That combination is worth breaking down. The Numbers The founder shared these publicly: combined web and mobile revenue is running around $25K/month, split roughly evenly between a Stripe-powered website and a mobile app on RevenueCat. Mobile has under 400 active subscribers. Pricing is aggressive for a mobile app, $10/week, or about $60/year, which works because it's solving a moment of real frustration rather than sitting as a passive subscription people forget about. Worth noting: these numbers come from a founder interview, so treat them as a snapshot of where the business was at that point rather than a live dashboard. The shape of the story, fast growth on a narrow niche with aggressive pricing, is the part worth paying attention to. Marketing: Almost Entirely UGC The founder posted three times a day across Instagram, TikTok, YouTube, and Facebook. Most of it didn't land. Once a specific format started converting, he stopped experimenting and went all-in, bringing in UGC creators and running paid ads on top of the format that already worked. That's the actual playbook: post relentlessly, watch for the one format that converts, then stop spreading effort thin and pour it all into what's already working. The Pattern Behind It The reason this works isn't guitar tone specifically. It's a translation problem: someone sees a result they want, but the instructions that got that result assume gear they don't have. The gap between "here's what worked for them" and "here's

2026-07-22 原文 →
AI 资讯

Your Error Messages Are Written for Developers, Not Users

Open the network tab on almost any web app, trigger a failed request, and you'll usually find one of two things staring back at the user: a raw stack trace, or a message so generic it might as well say "something happened." Neither one helps. Both exist for the same reason they were written by developers, for developers, and never translated for the person actually using the product. The Error Message Nobody Designed Most UI elements go through some level of design scrutiny. Buttons get spacing decisions. Forms get validation states. But error messages? They're usually whatever string got thrown at the moment something broke, copy-pasted straight from a try/catch block into a toast notification. "Error 500: Internal Server Error." "Failed to fetch." "Unexpected token in JSON at position 4." These are diagnostic breadcrumbs for engineers debugging a system. To a user trying to submit a form or complete a purchase, they're just noise confirmation that something went wrong, with zero indication of what to do next. This is where good web app design services earn their keep not in the buttons and layouts everyone notices, but in the failure states nobody plans for until users start complaining. Why This Keeps Happening It's not that teams don't care. It's that error handling sits at the intersection of two disciplines that rarely talk to each other at the moment. Backend logic throws whatever exception the code produces. The front end just needs something to display so the app doesn't silently freeze. Nobody's job, at that moment, is to ask: "what should the user actually understand right now?" The result is a UI layer that's polished everywhere except the one place users encounter when things go wrong which, ironically, is exactly when clear communication matters most. What a Good Error Message Actually Does A well-designed error message does three things a raw exception never does. It tells the user what happened, in plain language not "Error: NetworkException," but "W

2026-07-21 原文 →
AI 资讯

I built a vector topographic contour map generator for designers (SVG export)

Hey everyone! 👋 As a designer, I constantly needed high-quality vector topographic contour lines and generative patterns for branding, UI hero backgrounds, and print projects. Most existing tools were either heavy GIS software (like QGIS) or required static file purchases. So I built Topolines —a fast, web-based vector topographic generator. 🎛️ Key Features: Parametric Control: Fine-tune elevation density, noise scale, detail, and line weights in real-time. Custom Styling: Full visual control over color palettes, gradients, contrast, and backgrounds. Clean Vector Export: Instant SVG exports (perfect for Figma, Illustrator, or web code) and HD PNGs. Frictionless Free Tier: Direct PNG exports without even needing an account. I'd love for you to try it out at topolines.app and let me know your feedback or feature requests!

2026-07-21 原文 →
AI 资讯

How We Split a Legacy Monolith Into Microservices Without a Single Outage

8 min read · telecom provisioning platform, 30M+ subscribers Most companies avoid migrating their monolith for one reason: they imagine it as a single, terrifying event — months of a feature freeze, a weekend cutover, and a rollback plan that's really just hope. That fear is reasonable. A big-bang rewrite of a live system serving 30M+ subscribers really would be terrifying. So we didn't do that. We used a pattern that lets you migrate a monolith one slice at a time, while the system keeps running and the product team keeps shipping features — the same pattern Martin Fowler named Strangler Fig , after the vine that grows around a host tree, gradually taking over, until eventually the original tree is no longer needed. Why the "just rewrite it" instinct is usually wrong The instinct to rewrite a legacy monolith from scratch is understandable — the old code is scary, undocumented, and nobody wants to touch it. But a full rewrite has a well-known failure pattern: it takes far longer than estimated, the business can't freeze feature development for that long, and by the time the rewrite is "done," the old system has changed underneath it and the rewrite is already out of date. The alternative isn't "don't migrate." It's: migrate in slices small enough that each one is boring , and never require the business to stop shipping while you do it. The pattern: a facade, and one slice at a time Strangler Fig works by putting a routing layer — a facade or API gateway — in front of the monolith. At first, 100% of traffic passes through to the old system untouched. Then, one capability at a time: Build the new version of that one capability as an independent service. Update the facade to route just that capability's traffic to the new service. Run both in parallel long enough to trust the new one (see "shadow traffic" below). Retire that piece of the old monolith. Repeat for the next capability. At every point in this process, the system is fully functional. There's no "half-migrat

2026-07-20 原文 →
AI 资讯

How to Apply PCB Design Standards for Better Product Design

Nothing is more frustrating than spending hours, or even days, perfecting a PCB design only to discover it fails during production. The secret to avoiding this is simple: apply PCB design standards from the very beginning. These guidelines act as a blueprint for reliability, manufacturability, and long-term performance, guiding every aspect of your board—from trace widths and spacing to via placement, solder mask, and layer stackups. Following these recommended practices doesn’t just prevent manufacturing errors—you save time, reduce costs, improve quality, and minimize delays. Whether you’re building a prototype or preparing for full-scale production, designing with these rules in mind ensures your PCB performs exactly as intended. Applying these best practices sets the foundation for success in any production scenario. By starting with the right standards, you can avoid costly mistakes before they happen and bring your product to life smoothly. Why PCB Design Standards Matter (More Than You Think) PCB standards are not theoretical rules. They are: • Proven engineering practices • Built from real-world failures • Designed to reduce risk Without them, you are basically designing blindly. With them, you get: • Higher first-pass success rate • Faster manufacturing approval • Reduced rework and cost • Better product reliability Steps to Apply PCB Standards in Your Design Here’s a practical, step-by-step guide to apply PCB design standards effectively: Step 1: Start with the Right Standards (Not All Are Needed) You don’t need to follow everything. You need to follow the right ones. Key standards to consider: • IPC-2221 → General PCB design standard • IPC-7351 → Footprint design guidelines • IPC-A-600 → PCB acceptability • IPC-A-610 → Assembly quality Practical Tip: Start with IPC-2221 + IPC-7351 if you're doing design. Step 2: Apply Standards During Component Placement Most failures start here—not routing. Common Mistakes: • Random component placement • Ignoring signal

2026-07-20 原文 →
AI 资讯

TDA (Tell Don't Ask)

Introdução A visão original de Kay para OOP não era "objetos com dados públicos que outros manipulam", era objetos que trocam mensagens e decidem sozinhos o que fazer com elas. é Tell dont ask é basicasmente um resgate dessa ideia original, porquer com o tempo muita gente passou a usar OOP como “structs com getters e setters”, pedendo o encapsulamento de verdade. Ideia Central Exemplo do Cliente e Carteira Ask Eu PERGUNTO o saldo, e EU decido o que fazer com ele if ( cliente . carteira . saldo >= 50 ) { cliente . carteira . saldo -= 50 ; } else { console . log ( "saldo insuficiente" ); } Tell Eu DIGO pro cliente pagar, e ELE decide o que faze // "Tell" — eu DIGO pro cliente pagar, e ELE decide o que fazer cliente . pagar ( 50 ); class Cliente { carteira : Carteira ; pagar ( valor : number ) { if ( this . carteira . saldo < valor ) { throw new Error ( "saldo insuficiente" ); } this . carteira . saldo -= valor ; } } Repare a diferença de responsabilidade: No "Ask", quem chama o código precisa saber a regra ("se o saldo for menor, não pode pagar") e tomar a decisão sozinho. No "Tell", o próprio objeto conhece sua regra e decide por dentro. Quem chama só diz o que quer que aconteça. Por que "perguntar" é perigoso Pensa no "Ask" espalhado pelo sistema: toda tela, todo botão, todo endpoint que cobra do cliente vai ter que copiar essa mesma verificação de saldo: if ( cliente . carteira . saldo >= valorDoCarrinho ) { ... } if ( cliente . carteira . saldo >= valorDaAssinatura ) { ... } if ( cliente . carteira . saldo >= valorDoBoleto ) { ... } Se um dia a regra mudar (por exemplo, "clientes VIP podem ficar com saldo negativo até -R$100"), você precisa caçar todos esses lugares e mudar um por um. É praticamente garantido que algum lugar vai ser esquecido — e aí seu sistema tem um bug de regra de negócio inconsistente. Com "Tell", a regra mora em um lugar só ( Cliente.pagar ). Mudar uma vez, resolve todo o sistema. Como isso conecta com Law of Demeter Os dois princípios andam

2026-07-19 原文 →
AI 资讯

LOD (Law of Demeter)

Introdução O nome do princípio vem do próprio nome do projeto de pesquisa (que remete a Deméter, deusa grega da agricultura — a metáfora era "cultivar" software que cresce de forma incremental e adaptável, não do princípio de acoplamento em si). O projeto Demeter investigava como reduzir o custo de manutenção de sistemas orientados a objetos observando que boa parte das mudanças de software quebrava código muito distante do ponto onde a mudança real acontecia — um efeito cascata causado por classes que conheciam profundamente a estrutura interna de outras classes. Essa observação foi confirmada empiricamente alguns anos depois: em 1994, Chidamber & Kemerer publicaram as famosas métricas CK ( A Metrics Suite for Object Oriented Design ), nas quais o CBO (Coupling Between Objects) — quão acoplada uma classe é a outras — se tornou um dos preditores mais fortes de defeitos e esforço de manutenção em estudos empíricos posteriores de engenharia de software. Ou seja: a intuição por trás da Law of Demeter (menos acoplamento = menos bugs ao mudar código) tem respaldo em dados de décadas de pesquisa empírica em qualidade de software. Definição Também chamada de "Principle of Least Knowledge" , a formulação clássica é: Um método M de um objeto O só deve chamar métodos de: O próprio O Os parâmetros recebidos por M Qualquer objeto que M crie/instancie internamente Os componentes diretos de O (seus atributos/campos) Variáveis globais acessíveis a O Resumo popular: "use apenas um ponto" — evite código como: pedido . getCliente (). getEndereco (). getCidade (). getNome () Isso é conhecido como "train wreck" (trem de vagões) — cada . é um vagão acoplado ao anterior. Se a estrutura interna de Cliente ou Endereco mudar, todo código que fez essa travessia quebra, mesmo estando em um módulo completamente não relacionado. Porque isso importa na prática? Quando o método M faz objeto.getX().getY().metodo() , ele passa a depender da estrutura interna de X e Y , não só da interface pública d

2026-07-19 原文 →
AI 资讯

Google is open-sourcing its 3D emoji

Now, if you want to, you can use Google's 3D emoji in your own creations. The company shared some details about how it went about designing the little pictograms and why, as part of World Emoji Day on Friday. Things you might not necessarily worry about in a 2D illustration suddenly become very important when […]

2026-07-19 原文 →
AI 资讯

LLD Domain Modeling: How to Debug Your Design When It Feels “Wrong”

Every engineer eventually hits this phase: “My design looks okay… but something feels off.” No compile errors. No obvious bugs. But still: responsibilities feel scattered services feel too big entities feel too thin logic feels duplicated boundaries feel unclear This is normal. Because domain modeling is not about getting it right in one attempt. It is about refining structure until the business behavior becomes clear. Step 1 — Start With the Symptom, Not the Code If your design feels wrong, don’t immediately rewrite everything. First identify the symptom: Common symptoms: too many “Manager” services logic repeated in multiple places unclear ownership of rules too many dependencies between modules frequent “if-else explosion” Each symptom points to a specific modeling issue. Step 2 — Check If Invariants Are Scattered Ask: “Where are my business rules living?” Bad sign: Rules inside services + controllers + helpers This leads to: inconsistent behavior duplicated validation broken business guarantees Good design: invariants live close to the entity or aggregate root Step 3 — Check Entity vs Service Confusion A very common issue: Entities become dumb: only fields no behavior Services become overloaded: all logic all rules all decisions This creates: Anemic Domain Model + Fat Services Fix mindset: Entity = owns behavior + protects state Service = coordinates workflows Step 4 — Check Your Aggregate Boundaries Ask: “What must stay consistent together?” If your answer is unclear, you likely have: wrong aggregates or missing aggregates Example problem: Cart and Order sharing logic This causes: inconsistent pricing unclear lifecycle ownership Fix: Cart = intent Order = truth Step 5 — Look for “Hidden Coupling” Hidden coupling happens when: one module depends on internal state of another multiple services modify same data business rules are duplicated across boundaries This leads to fragile systems. Strong design ensures: each domain owns its own truth. Step 6 — Validate Stat

2026-07-18 原文 →
AI 资讯

Building Reliable Event-Driven Systems: Event Schemas, Versioning, Contract Testing and Events vs Commands (part-3)

In this article, we're going to explore Event Schema evolution with Event versioning 10. Event Schemas Will Eventually Change No event schema stays the same forever. As businesses grow, regulations shift, products gain new features, and processes become more complex, the data shared between services must evolve as well. This evolution is not optional—it is a natural consequence of a system adapting to changing requirements. Many teams initially assume they can simply update an event whenever needed. This assumption may hold when there is only one producer and one consumer, but real-world systems rarely remain that simple. Over time, multiple consumers emerge, each with its own responsibilities and release cycles. A typical system often looks like this: OrderConfirmed | +------------------+-------------------+ | | | v v v Inventory Billing Notification | v Analytics | v Customer Insights Each consumer evolves independently. Some services may deploy updates weekly, while others might release changes quarterly. In some cases, consumers may even belong to external teams with entirely different priorities and timelines. Because of this, producers cannot assume that all consumers will upgrade simultaneously. Schema evolution, therefore, is not just about modifying data structures. It is fundamentally about maintaining compatibility across independently evolving systems. Compatibility Is More Important Than Version Numbers When discussing schema evolution, teams often focus immediately on versioning. While versioning is useful, compatibility is far more critical. Without compatibility, versioning alone cannot prevent system breakage. Consider the following event: { "orderId" : "ORD-1001" , "customerId" : "CUS-501" , "totalAmount" : 249.99 } Now imagine a new requirement introduces currency. One approach might replace the existing field entirely: { "orderId" : "ORD-1001" , "customerId" : "CUS-501" , "amount" : { "value" : 249.99 , "currency" : "USD" } } Although the data mo

2026-07-17 原文 →
AI 资讯

“Safe AI for Teens” Needs a Recoverable Escalation Flow, Not One Generic Refusal

OpenAI published “Why teens deserve access to safe AI” on July 16, 2026, describing its approach around learning, age-appropriate safeguards, parental controls, and work with external experts and organizations. Primary source: OpenAI, “Why teens deserve access to safe AI” . This raises a concrete product-design question for any teen-facing AI experience: after a safeguard intervenes, can the user understand what happened and continue toward a legitimate goal? A generic “I can't help with that” may block harmful output, but it can also strand a learner, conceal an emergency path, or encourage prompt reformulation without increasing safety. Below is a design hypothesis and research plan—not a claim about OpenAI's current interface. Design three outcomes, not one refusal request -> proceed with age-appropriate help -> redirect to a safer learning path -> escalate urgent risk to immediate support options The system should not expose its detection thresholds or provide a bypass recipe. It should explain the next safe action in plain language. Annotated response pattern [1] Clear boundary I can't help plan ways to hurt yourself. [2] Immediate check Are you in immediate danger right now? [3] Reachable actions [Call local emergency services] [Contact a trusted adult] [View crisis resources] [4] Safe continuation I can stay with you while you choose someone to contact, or help write a message. [5] Privacy explanation If this experience shares information with a parent or guardian, explain what, when, and why before asking the user to continue, except where law or immediate safety obligations require otherwise. Annotations: Boundary names the category without scolding. Check uses a direct, answerable question. Actions are not hidden in a paragraph. Continuation gives the conversation a safe purpose. Privacy avoids promising confidentiality the product cannot guarantee. Emergency resources must be localized and maintained by qualified teams. Do not hard-code one country's numb

2026-07-17 原文 →