AI 资讯
Effective Engagement Management in Enterprise Architecture Projects
Communication and Stakeholder Management Successfully executing enterprise architecture projects requires more than just technical expertise. The key to success lies in effective engagement management, where communication and stakeholder management play a central role. In this post, we’ll explore strategies and tactics for successfully engaging stakeholders in complex IT projects and enterprise architecture initiatives. The Challenge: Complexity and Different Perspectives Enterprise architecture projects are often characterized by high complexity. They span various business units and teams, from IT to management and external service providers. These projects are not only technologically demanding but also require close collaboration between all involved parties. Each stakeholder brings their own perspectives, priorities, and objectives, which increases the risk of misunderstandings, delays, and misaligned outcomes. The Key to Success: Engagement Management Effective engagement management ensures that all stakeholders are involved from the start and that their needs and expectations are understood. This involves not only regular communication but also a structured and strategic approach. Below are some proven strategies to achieve successful engagement: 1. Early and Comprehensive Stakeholder Mapping Successful engagement begins with a clear understanding of the involved stakeholders. Stakeholder mapping helps identify all relevant actors, their interests, and their potential influence on the project. The following questions should be considered: Who are the internal and external stakeholders? What are their expectations for the project? How much influence do they have on decision-making? What are their communication needs? A comprehensive stakeholder mapping allows for the establishment of clear communication paths and consideration of specific needs from the start. 2. Transparent Communication One of the most common causes of project failure is insufficient or ineff
AI 资讯
Too Many Req: A Bucket List Guide to Building a Rate Limiter
Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. Star git-lrc to help devs discover the project. Do give it a try and share your feedback. Every serious API will eventually tell you to sit down and be quiet. Hammer GitHub, Stripe, or AWS a little too eagerly and your requests start bouncing back with a polite but firm 429 . I always found that fascinating, so let's build the thing that says no. By the end of this post we'll have designed a rate limiter that actually holds up when you put it in front of real traffic, and I promise to only make a reasonable number of bucket puns along the way. A rate limiter does one job: it decides how many requests a client is allowed to make in a given window of time. It protects your system from getting flattened, and it keeps one greedy user from eating everyone else's lunch. Simple idea. Surprisingly spicy implementation. Let's build it up piece by piece, the way you'd actually reason through it in an interview or a design doc. First, what are we even building? Before writing a single line, let's agree on what "good" looks like. Here's my wishlist: Configurable limits. Something like "100 requests per minute per user." The rules should not be hardcoded, because free users and premium users deserve different amounts of pain. Honest rejections. When someone goes over, we return HTTP 429 Too Many Requests and include helpful headers telling them how many requests they have left and when the window resets. No mystery. Barely-there latency. This check runs on every single request , so it has to be fast. Let's aim for under 3ms at P95. If your rate limiter is slow, congratulations, you built a second bottleneck. Highly available and shared. Multiple servers need to agree on the same counts. More on why that word "shared" is doing a lot of heavy lifting later. Cool. Now let's start naive and let reality punch us in the face a few times. Attempt 1:
AI 资讯
What if you don't have to build a login page again?
How do you usually build a login page in an application? The first project Imagine you are working on a project that needs a login page. Let's call it Aurora (Project A). The login page is the entry point to the application. Users who have access can log in to the application with the permissions they have. We are not going to talk about the details of the login method yet, such as email + password, username + password, phone + password, social login, magic link, or others. Let's say we use email + password for this example. For this, we usually need user data for the application, for example a users table in the database. If we use email and password as the login method, the users table would at least need email and password columns. Of course, the password should be hashed. After the application is developed, users can log in using the email and password registered in the database. During development, we can simply inject user data directly into the database. Adding one or two users manually is still fine. If we need more users, we can create a database script to insert them. Then another requirement appears. We need to manage users directly from the application. Previously, user data could only be accessed directly from the database. Now the application needs to show a list of users, user details, and provide features to create, update, and delete users. We need to build several new pages for this user management feature. Eventually, the feature is completed. Now you can add users whenever you want, and they can immediately use their account to log in to Aurora. At this point, the user requirements for Aurora might be enough. The second project Then you have another project that also needs a login page. Let's call it Borealis (Project B). This is a different project from Aurora, but the login works in a similar way. Since you already built the login feature in the previous project, you can duplicate the existing code into Project B, including the user management
AI 资讯
ByteByteGo in 2026: Is It Still Worth It for System Design Interview Prep?
Disclosure: This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided in this article. Credit - ByteByteGo Hello Devs, if you're preparing for a System Design interview in 2026 , there is a good chance you've come across ByteByteGo and its founder, Alex Xu, author of another popular System Design interview resource and book, the System Design Interview - An Insider's Guide . But with so many system design courses, books, YouTube channels, newsletters, and interview platforms available today, an important question remains: Is ByteByteGo still worth it for System Design interview preparation in 2026? After spending considerable time exploring the platform and Alex Xu's system design material, my answer is yes — especially if you prefer visual, structured, and practical explanations of complex distributed systems. What makes ByteByteGo particularly interesting is that it has grown beyond the original system design material. The platform now covers areas such as Object-Oriented Design, Machine Learning System Design, Generative AI System Design, and Coding Interview Patterns , all the important topics you need to master to crack any FAANG-level interview. The biggest strength, however, remains the same: making complicated system design concepts easier to understand through diagrams, examples, trade-offs, and real-world case studies. In this article, I'll take a fresh look at ByteByteGo in 2026, explain what it offers, who should use it, what you'll learn, and whether I think it's worth paying for. If you're already looking for a system design resource, you can check out ByteByteGo here . What Is ByteByteGo? ByteByteGo is an online learning platform created by Alex Xu , the author of the popular System Design Interview — An Insider's Guide books. The platform started with a strong focus on system design interview preparation and has evolved into a broader technical learning resource. One of the t
AI 资讯
Bulletproofing AI Agents: How to Prevent $2,000 Infinite API Loops
Implement multi-layer circuit breakers, payload hashing, and financial cutoffs before an autonomous agent drains your backend. The Bottleneck in Production Autonomous AI agents running in tool-use loops fail unpredictably. When an LLM encounters an unexpected schema, a transient network error, or an ambiguous prompt, it often enters a hallucinated retry storm. In standard web apps, a runaway loop hits a rate limit or returns a 500 Internal Server Error . In agentic architectures, an unconstrained ReAct loop executes external API calls continuously, burning tokens, exhausting upstream quotas, and running up massive cloud bills in minutes. Here is the anti-pattern running in far too many codebases: # Anti-pattern: Unbounded autonomous agent loop while not task_complete : action = llm . decide_action ( state ) result = external_api . call ( action . endpoint , action . params ) state = update_state ( result ) If the LLM fails to transition state due to an unparseable response, this loop runs indefinitely. Cloud providers do not issue refunds for self-inflicted API usage. The System Architecture & Fix To make AI agent tool execution production-safe, never allow direct API calls from agent code. Route every external request through an isolated API Safety Wrapper implementing three distinct layers of defense: Deterministic Request Firewall: A hard cap on execution count per task session (Time-To-Live counter). Sliding-Window Loop Detector: Hashing outgoing request payloads to catch repetitive or oscillating tool invocations. Financial Kill Switch: A pre-flight budget validator that cuts credentials immediately if projected cost exceeds session limits. [ AI Agent Engine ] │ ▼ [ API Safety Wrapper ] ├── 1. Call Counter Check (Limit < N) ├── 2. Hash Duplicate Detector (Window: last 3 calls) └── 3. Pre-flight Cost Estimator (Budget < Limit) │ ┌────┴──────────────────────────┐ [ Passed ] [ Tripped ] │ │ ▼ ▼ [ External Upstream API ] [ Emergency Kill Switch ] (Revoke Token & Ab
AI 资讯
Your AI doesn't understand design. So I gave it a library it can read.
Ask any LLM to "make this landing page look like a high-end Swiss design studio" and you'll get something that gestures at the idea — a sans-serif font, some whitespace, maybe a red accent because it half-remembers Müller-Brockmann. It looks AI-generated because it is. The model has read a billion words about design but has no grounded, reusable representation of what "Swiss International Style" actually specifies: the exact grid, the type scale, the spacing ramp, the rules for what you must not do. That gap is the whole problem. Models are great at language and bad at design systems, because a design system isn't language — it's a set of constrained values plus the discipline to apply them consistently. So I built the missing piece: a library of real design styles, turned into something a machine can actually consume. It's called Curio . This post is about the part I think is interesting to other builders: making design machine-readable, and publishing the catalog for agents instead of for humans. A design style is just tokens + rules The insight is boring and that's why it works. Pick any coherent visual language — Bauhaus, Memphis, the Edo woodblock palette, Stripe's product aesthetic — and you can decompose it into: Tokens : color families, type families and scale, spacing ramp, radii, shadow/elevation, motion timing. Components : how a button, card, input, nav actually look in this language. Rules : the "always" and the "never." (Swiss: never center body text, never more than two weights. Memphis: never subtle.) Once a style is expressed that way, an AI doesn't have to imagine the look. It interpolates within a fixed, internally-consistent set of values. The output stops looking like a guess because it isn't one. Each style in Curio is packaged exactly like this — tokens, component specs, and an explicit "avoid" list — as a DESIGN.md file — markdown with YAML frontmatter — that a model can read in one shot ( what is DESIGN.md? ). # excerpt of a design package a
AI 资讯
How ChatGPT Serves 900 Million Users at a Time
Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is...
AI 资讯
The Criteria pattern in NestJS: what a client may ask for is a file, not a signature
The Criteria pattern in NestJS One single way to filter, sort and paginate any list. Five parameters and a find() The example running through this article is a library catalogue. A book stores this: // src/book/book.schema.ts @ Schema ({ timestamps : true }) export class Book { @ Prop () title : string ; @ Prop ({ type : Types . ObjectId , ref : " Author " }) author : Types . ObjectId ; @ Prop () publishedAt : Date ; @ Prop () copies : number ; // copies on the shelf @ Prop () available : boolean ; @ Prop () acquisitionPrice : number ; // what it cost us: internal, never published } The author's name is not here: it lives in the authors collection, on the other side of that reference. And the screen consuming the catalogue is a table with a search box, per-column filters and pagination. The endpoint feeding it is written once and grows by accretion. It starts returning a page with a fixed order, and by the time the table has all its filters it has become this: // src/book/book.controller.ts @ Controller ( " books " ) export class BookController { constructor ( @ InjectModel ( Book . name ) private readonly model : Model < BookDocument > , ) {} @ Get () async getAll ( @ Query ( " title " ) title ?: string , @ Query ( " available " ) available ?: string , @ Query ( " minCopies " ) minCopies ?: string , @ Query ( " sortBy " ) sortBy ?: string , @ Query ( " page " ) page ?: string , ) { const filter : FilterQuery < BookDocument > = {}; if ( title ) { filter . title = { $regex : title , $options : " i " }; } if ( available ) { filter . available = available === " true " ; } if ( minCopies ) { filter . copies = { $gte : Number ( minCopies ) }; } const current = Number ( page ?? 1 ); const [ items , total ] = await Promise . all ([ this . model . find ( filter ) . sort ({ [ sortBy ?? " createdAt " ]: - 1 }) . skip (( current - 1 ) * 20 ) . limit ( 20 ), this . model . countDocuments ( filter ), ]); return { items : items , total : total , page : current }; } } There are co
AI 资讯
El patrón Criteria en NestJS: lo que un cliente puede pedir es un archivo, no una firma
Cinco parámetros y un find() El ejemplo de todo el artículo es el catálogo de una biblioteca. Un libro guarda esto: // src/book/book.schema.ts @ Schema ({ timestamps : true }) export class Book { @ Prop () title : string ; @ Prop ({ type : Types . ObjectId , ref : " Author " }) author : Types . ObjectId ; @ Prop () publishedAt : Date ; @ Prop () copies : number ; // ejemplares en la estantería @ Prop () available : boolean ; @ Prop () acquisitionPrice : number ; // lo que costó adquirirlo: interno, no se publica } El nombre del autor no está aquí: vive en la colección authors , al otro lado de esa referencia. Y la pantalla que consume el catálogo es una tabla con buscador, filtros por columna y paginación. El endpoint que la alimenta se escribe una vez y crece por acumulación. Empieza devolviendo una página con un orden fijo, y para cuando la tabla tiene todos sus filtros ha llegado a esto: // src/book/book.controller.ts @ Controller ( " books " ) export class BookController { constructor ( @ InjectModel ( Book . name ) private readonly model : Model < BookDocument > , ) {} @ Get () async getAll ( @ Query ( " title " ) title ?: string , @ Query ( " available " ) available ?: string , @ Query ( " minCopies " ) minCopies ?: string , @ Query ( " sortBy " ) sortBy ?: string , @ Query ( " page " ) page ?: string , ) { const filter : FilterQuery < BookDocument > = {}; if ( title ) { filter . title = { $regex : title , $options : " i " }; } if ( available ) { filter . available = available === " true " ; } if ( minCopies ) { filter . copies = { $gte : Number ( minCopies ) }; } const current = Number ( page ?? 1 ); const [ items , total ] = await Promise . all ([ this . model . find ( filter ) . sort ({ [ sortBy ?? " createdAt " ]: - 1 }) . skip (( current - 1 ) * 20 ) . limit ( 20 ), this . model . countDocuments ( filter ), ]); return { items : items , total : total , page : current }; } } El método tiene decisiones correctas dentro: el total sale del mismo filtro que los
开发者
LISKOV SUBSTITUTION PRINCIPLE
A parent class must be able to be substituted by its child classes without breaking the application. In practice, this helps to organize the idea of inheritance, as it prevents us from extending a parent class only to later remove an already implemented method or do a “throw new Error(‘Not implemented’)”. Making us much more careful during planning. THE BIGGEST SYMPTOM OF ERROR Unfortunately, it is a symptom that appears late, but it is exactly when we are going to make a new implementation. You realize you violated Liskov when you are going to build a class or subclass and need to purposely throw an error in the implementation of a method. Exactly because that method shouldn't be there, but it is. A BAD EXAMPLE For example, in a delivery system. In this case, the “Delivery” class should be the parent/base for the other implementations. But the ‘MotoboyDelivery’ class breaks this. Code Example: // BAD: The subclass breaks the parent class contract. class Delivery { public calculateShipping (): number { return 15.0 ; } public getTrackingCode (): string { return " TRK123456789 " ; } } class MotoboyDelivery extends Delivery { public calculateShipping (): number { return 8.0 ; } // ERROR! There is no tracking code. public getTrackingCode (): string { throw new Error ( " Motoboys do not have a tracking code. " ); } } THE SOLUTION For those who do not yet know the 'Liskov Substitution Principle', it might seem that fitting in a sequence of 'if's is the solution. But in reality, the ideal path is to rethink how this abstraction is built. A good guiding principle is to think that a child class must always be able to take the place of the parent, without breaking the application. A GOOD EXAMPLE Still in the delivery system. ‘Delivery’ now has ‘TrackableDelivery’ in the middle of the way. With this, each “leaf”/edge of the application inherits what makes the most sense and nothing is broken. Code Example: interface Delivery { calculateShipping (): number ; } interface Trackab
开发者
Wireframing Software Compared: Features, Pricing & Use Cases
You’ve got a product idea, a deadline creeping closer, and a blank canvas staring back at you, so...
AI 资讯
How I Built a Color Picker That Actually Converts Colors Correctly (HEX/RGB/HSL)
While working on a design system recently, I kept running into the same frustrating problem: I'd grab a color from Figma in HEX format, need it in HSL for a CSS variable, and end up bouncing between three different websites just to convert one value. Each site had its own UI quirks, some required JavaScript to be enabled, and none of them gave me a proper color scheme alongside the conversion. So I did what any reasonable developer would do — I built my own. Because apparently I enjoy reinventing wheels. The Problem With Existing Solutions The existing color converter tools online weren't bad, but they had a few issues that bugged me: They were slow — many loaded heavy JavaScript libraries just to do simple math They lacked context — I wanted to see complementary colors and schemes alongside the conversion They were ad-heavy — I don't want to dodge pop-ups while trying to match a shade of blue I wanted something that felt like a native tool: instant, offline-capable, and comprehensive. A single HTML file that I could open, use, and close without ceremony. The Architecture Decision The first decision was whether to use a library or write the conversion logic myself. Libraries like color (npm) are battle-tested, but they add weight. Since this is a browser-only tool with no build step, I decided to write the conversions in vanilla JavaScript. Here's the core conversion logic that handles the heavy lifting: function hslToRgb ( h , s , l ) { s /= 100 ; l /= 100 ; const k = n => ( n + h / 30 ) % 12 ; const a = s * Math . min ( l , 1 - l ); const f = n => l - a * Math . max ( - 1 , Math . min ( k ( n ) - 3 , Math . min ( 9 - k ( n ), 1 ))); return [ Math . round ( f ( 0 ) * 255 ), Math . round ( f ( 8 ) * 255 ), Math . round ( f ( 4 ) * 255 )]; } This is the most concise HSL-to-RGB conversion I know. It's a compact version of the standard formula that avoids the typical case-based approach. The math checks out for all edge cases, including grayscale (when s = 0 ). AI-Assi
AI 资讯
Beyond Writing Code: The Core Mindset of a Modern Software Engineer
Many beginner developers believe software engineering is all about mastering programming languages, framework syntaxes, and clearing error logs. In reality, writing code is only a fraction of the actual job. The true core of software engineering lies in analyzing complex domain problems, evaluating deep trade-offs, and designing robust systems that stand the test of time. Let's explore what it genuinely takes to transition from a coder to a modern software engineer with the right engineering mindset. 1. Writing Code vs. Solving Problems Anyone with a healthy brain can learn syntax and write functional scripts after a few tutorials. However, the real engineering challenge begins long before you touch your IDE. Understanding the Domain: Breaking down business logic and user requirements. Evaluating Alternatives: Assessing whether a feature needs a complex custom hook or a simple native state. Long-term Value: Building solutions that won't break when requirements shift tomorrow. 2. The Importance of Maintainability Code is read much more often than it is written. When you are working on large-scale applications, you are never coding alone—even if you are solo for now, your future self is essentially a stranger six months down the line. Crafting clean, self-documenting code with meaningful, intention-revealing names. Enforcing single-responsibility functions to keep modules decoupled. Using predictable patterns so teammates can navigate and scale the application without getting buried in technical debt. 3. Pragmatic System Design and Trade-offs There is no silver bullet in software engineering. Every architectural decision—whether choosing a database, state management library, or caching strategy—comes with heavy trade-offs. Performance vs. Development Speed: Knowing when to optimize early and when to ship MVP code. Scalability vs. Complexity: Avoiding over-engineering simple features just because a shiny new tool exists. Balancing Constraints: A great engineer evaluate
AI 资讯
Architecting the New Operating System: A Guide to Context Engineering
Prompt engineering is a conversation; context engineering is system architecture. In the early days of working with Large Language Models (LLMs), optimizing the prompt was enough for simple text generation tasks. But when you are building autonomous systems—like a self-hosted automation server connecting cloud databases, webhooks, and reasoning nodes—prompts alone will not keep track of APIs, past decisions, and strict output constraints. Think of the LLM as the CPU, and the context window as the RAM. Context engineering is the discipline of treating that memory as a scarce resource, meticulously designing the pipeline that feeds the model the exact facts, instructions, and tools it needs at the precise moment it needs them. The Four Core Strategies To shift from vibe-coding a chatbot to architecting a resilient multi-agent system, you must manage what enters and stays in the context window using four primary techniques: Select: Decide exactly which external sources—like database schemas or specific API documentation—enter the context window to maximize the signal-to-noise ratio. Compress: Shrink the context payload only after the key facts are successfully structured. Write: Persist the task state and intermediate decisions outside the active context window so the agent can retrieve them later. Think of this as giving the agent its own local-first markdown vault for networked thought. Isolate: Separate contexts when domains collide. Instead of forcing one model to do everything, build multi-agent systems where each agent receives a strictly scoped slice of the context. Navigating the Failure Modes Stuffing a massive context window with raw JSON logs and unstructured data is a recipe for disaster. When building complex workflows, you must engineer guardrails against these critical failure modes: Context Poisoning: Hallucinated or incorrect information enters the context and compounds over time because the agent continually reuses it. Context Distraction: The agent g
AI 资讯
Introduction to the Cloud-Native World with Azure Kubernetes Services (AKS) - Series Part 6
With the Azure Kubernetes Services (AKS) platform, containerized workloads can be efficiently managed and scaled. However, the full potential of AKS is only realized when it is seamlessly integrated with other Azure services. This enables a complete cloud-native environment that is scalable, secure, and automatable, while providing maximum flexibility. In this final post of the series, we will show you how AKS can be integrated with other Azure services to create a robust and holistic platform for your applications. Why Integrating AKS into the Azure Cloud Is Crucial AKS provides a highly available and scalable infrastructure for managing containerized applications. However, integrating it with other Azure services like Azure DevOps, Azure Monitor, Azure Active Directory (Entra ID), and Azure Storage extends functionality and optimizes workload management. By leveraging Azure services alongside AKS, companies can: Ensure enhanced security for their containerized applications. Build robust monitoring and logging solutions to monitor the state of applications at all times. Set up automated pipelines for deployment and scaling. Seamlessly exchange data and status information across various Azure services. Key Azure Services to Integrate with Your AKS Platform Azure Active Directory (AAD) for Authentication and Security Azure Active Directory (AAD) provides comprehensive identity and access management that can be directly integrated with AKS. This ensures that only authorized users and services can access your Kubernetes clusters. With Azure RBAC (Role-Based Access Control), you can define granular access permissions for different users and teams, increasing the security of your environment. AAD Pod Managed Identities enable your AKS applications to securely access Azure resources like Azure Key Vault or Azure Storage without the need to manually manage sensitive credentials. Azure DevOps for CI/CD Pipelines Azure DevOps is one of the best solutions for automating CI/CD
AI 资讯
65% Mechanical Keyboard PCB: Design, Layout, and Manufacturing Considerations
The 65% mechanical keyboard has become a popular format for people who want a compact keyboard without giving up the dedicated arrow keys. Compared with a 60% keyboard, a typical 65% layout adds an arrow-key cluster and usually includes a small navigation area. Compared with a TKL keyboard, it removes the dedicated function row and reduces the overall footprint. For keyboard designers, however, reducing the physical size of the keyboard does not simply mean removing a few keys. The PCB has to accommodate the switch matrix, diodes, controller, USB or wireless circuitry, RGB lighting, mounting features, and sometimes hot-swap sockets within a relatively constrained outline. That makes the PCB one of the most important parts of a 65% keyboard design. What Is a 65% Mechanical Keyboard PCB? A 65% mechanical keyboard PCB is the circuit board designed specifically for a 65% keyboard layout. The exact key count and physical arrangement can vary between designs, so the term "65%" describes a form factor rather than one universal PCB specification. A typical board may contain: Mechanical switch footprints A switch matrix One diode per switch position A microcontroller USB connectivity or wireless circuitry Reset and boot controls Indicator LEDs Per-key RGB or underglow lighting Hot-swap sockets, when supported Mounting holes and mechanical cutouts The electrical design and physical design have to work together. A PCB can have a perfectly functional schematic and still fail to fit the intended keyboard case if the mounting holes, switch positions, USB opening, stabilizer locations, or board outline are not correct. Why the PCB Layout Matters So Much Keyboard PCBs are unusual compared with many conventional electronics boards because the PCB also defines part of the physical typing experience. The location of switch footprints determines the key positions. The mounting system affects how the PCB interacts with the case. Flex cuts can change the mechanical response of different
AI 资讯
The Rate Limiter Strikes Back: Designing a Token Bucket from Scratch
The Quest Begins (The "Why") I still remember the first time our API started choking under a sudden traffic spike. It was a Friday afternoon, the kind where you’re just about to log off, and the monitoring dashboard lit up like a Christmas tree. Requests were piling up, latency shot through the roof, and our users began seeing those dreaded “429 Too Many Requests” errors. We had a naive rate limiter in place—a simple fixed‑window counter that reset every minute. It worked fine when traffic was steady, but as soon as a burst hit, the counter would either let too many through (because we hadn’t hit the limit yet) or block everything for the whole minute (because we’d already exhausted the quota). It felt like trying to hold back a tsunami with a sandbag. Honestly, I was frustrated. I knew there had to be a smarter way to smooth out those bursts without penalizing honest users or over‑protecting the system. That’s when I dove into the world of rate‑limiting algorithms, and the token bucket caught my eye like a shiny loot drop in a dungeon. The Revelation (The Insight) The token bucket is deceptively simple, yet it solves the exact pain points we were experiencing. Imagine a bucket that holds a fixed number of tokens. Tokens drip into the bucket at a steady rate (say, 10 tokens per second). Each incoming request consumes a token. If the bucket is empty, the request is denied or delayed; if there’s a token, the request proceeds and the token is removed. Why does this beat the fixed‑window counter? Burst tolerance – The bucket can store up to its capacity, allowing a short burst of requests up to that limit without waiting for the next window. Smooth throttling – Because tokens are added continuously, the limiter adapts to the actual request rate rather than resetting abruptly at arbitrary intervals. Memory‑light – We only need to track two numbers: the current token count and the last time we refilled the bucket. No arrays of timestamps per key. Here’s a quick ASCII sket
AI 资讯
Your AI Agent Scheduler Needs a Clock-Skew Budget, Not Just Cron
A scheduler can be perfectly healthy and still run the wrong job at the wrong time. The failure is usually not the cron expression. It is the boundary between wall-clock time, monotonic elapsed time, leases, retries, and a process that may pause or restart. A reliable agent scheduler needs an explicit clock contract. Without one, a clock correction can make a job run twice, never run, or run after its authorization window has expired. The three clocks an agent should not conflate Use wall-clock time for human meaning and durable records: scheduled_at: when the user asked for the run not_before: the earliest acceptable dispatch time expires_at: the latest acceptable dispatch time Use a monotonic clock for elapsed-time decisions inside one process: lease renewal deadlines backoff timers watchdog intervals drain deadlines Use a database or provider sequence for ordering across processes: scheduler ownership fencing tokens attempt numbers reconciliation order A monotonic timestamp cannot be compared across hosts, and a wall-clock timestamp cannot safely measure a five-minute lease if NTP steps the clock backward. Store both kinds of evidence instead of pretending one timestamp answers every question. A small scheduling contract Here is a deliberately boring record shape: action: send_digest run_id: 01J... scheduled_at: 2026-08-19T08:00:00Z not_before: 2026-08-19T08:00:00Z expires_at: 2026-08-19T08:05:00Z lease_owner: worker-7 lease_token: 1842 attempt: 1 state: READY The important part is not the field names. It is the decision rule: The scheduler claims the run with a durable lease and fencing token. It checks wall-clock eligibility against not_before and expires_at. The worker checks that its lease token is still current before starting. The effect layer checks the token again before a side effect. If the outcome is ambiguous, record UNKNOWN and reconcile by the provider's idempotency key instead of blindly retrying. That last step matters after restarts. A clean rest
AI 资讯
Building a Location-Aware Discovery Engine: Why “Nearby” Isn't Just Distance
"Nearby" sounds like a simple feature. Calculate the distance between the user and every location. Sort by distance. Done. In practice, that's not enough. A useful local discovery engine has to understand more than geography. That's one of the problems we're tackling with LeeX. The basic version A traditional nearby query might look like: User location ↓ Calculate distance ↓ Sort ascending ↓ Return results If Restaurant A is 500 meters away and Restaurant B is 2 kilometers away, Restaurant A wins. But what if Restaurant A is permanently closed? What if Restaurant B is much more relevant to the user's category? What if Restaurant B is currently featured? What if thousands of people have recently interacted with Restaurant B? Distance alone doesn't capture usefulness. Our discovery model We're thinking about discovery as a combination of signals: Discovery Score = Distance + Relevance + Activity + Popularity + Featured status + Availability + User context The exact weighting can evolve. The important part is that proximity is one signal, not the entire algorithm. Distance still matters We don't want to ignore geography. For local discovery, distance is extremely important. A user looking for a restaurant probably cares whether it is: 500 m 1 km 2 km 5 km 10 km That's why LeeX can expose radius-based discovery. But distance should normally be combined with other information. Category context Suppose someone opens LeeX and selects: Restaurants The discovery engine should not treat every listing equally. The system already knows the user's current intent. That gives us a stronger query: Nearby + Restaurant + Open + Relevant rather than: Nearby + Everything Featured listings LeeX also has a promotion layer. Featured listings can receive additional visibility across relevant discovery surfaces. But promotional ranking needs to be handled carefully. A featured listing shouldn't necessarily make every other result useless. Instead, we can think of featured placement as an ad
AI 资讯
Design Patterns: Reusable Solutions to Recurring Problems
Design Patterns: Reusable Solutions to Recurring Problems A practical guide to classic design patterns in C#/.NET — Factory, Singleton, Repository, Strategy, and Mediator — covering what problem each one actually solves, working implementations, common .NET-specific variations, and honest guidance on when each pattern earns its complexity versus when it's unnecessary ceremony. Table of Contents Introduction Factory Pattern Singleton Pattern Repository Pattern Strategy Pattern Mediator Pattern How These Patterns Combine in Practice Patterns vs. Over-Engineering Common Pitfalls Quick Reference Table Conclusion Introduction Design patterns are named, reusable solutions to problems that recur often enough across software projects that giving them a shared name and shape is genuinely useful — not because the specific code is copy-pasteable, but because the name lets developers communicate a design intent quickly ("just make it a Strategy") instead of re-explaining the same structural idea from scratch every time. This guide covers five of the most commonly used patterns in .NET codebases, with working C# examples, and — consistent with this series' recurring theme — honest guidance on when each pattern is solving a genuine problem versus adding structure a simpler solution wouldn't need. // A pattern name compresses a whole design conversation into one word "Just inject an IPaymentStrategy and pick the implementation based on the payment method" // ← Strategy "Wrap the whole multi-step checkout process behind a single mediator call" // ← Mediator 1. Factory Pattern The problem: object creation logic that doesn't belong at the call site // ❌ The caller needs to know about every concrete shipping provider and how to construct each one IShippingProvider provider = order . Region switch { "US" => new UpsShippingProvider ( apiKey , region ), "EU" => new DhlShippingProvider ( apiKey , endpoint ), "APAC" => new FedExShippingProvider ( apiKey , credentials ), _ => throw new NotS