AI 资讯
The Art of Range Pricing in Software Projects: A Practical Guide for Agencies
Every software agency has been here: the client asks for a price, you give a range (say $45k–$65k), and two things can happen. Either the client nods and you win the deal at the low end — or they get suspicious and ask "so you don't actually know how much it costs?" Range pricing is often misunderstood. Used wrong, it looks like you're guessing. Used right, it's the most honest and professional way to price software projects — because anyone who gives you a single fixed number for an undefined project is either padding heavily or gambling with their margin. This guide covers when to use range pricing, how to structure it, and — most importantly — how to present it so clients trust you more, not less. Why Single-Point Pricing Is a Problem A fixed price for an undefined project forces you into one of two positions: You pad aggressively — add 40% contingency, quote $70k for a project you'd happily do for $50k. If the scope doesn't expand, the client overpays. If it does, you're protected. Either way, one party loses. You guess lean — quote $50k based on your best assumptions. If the client adds features mid-project, your margin evaporates. The client thinks they're paying for X, you're building X+Y. Both parties end up frustrated. A pricing range avoids both traps. It says: "based on what we know today, this project falls between $45k and $65k. Here's what needs to be true for the low end, and here's what would push it toward the high end." That's not guesswork. That's transparency. The Anatomy of a Good Pricing Range Not all ranges are created equal. A useful range has three properties: 1. Width That Respects Uncertainty The width of your range communicates how well you understand the project. Range width What it signals When it's appropriate < 15% ($50k–$57k) High confidence Detailed spec, similar past projects, known team 15–30% ($50k–$65k) Moderate confidence Clear brief, some unknowns in tech or integration 30–50% ($50k–$75k) Low confidence Vague brief, new domain
AI 资讯
Platform Engineering Maturity Emerges as a Key Differentiator for Enterprise AI Success
Platform engineering maturity is emerging as an important factor in determining whether organizations can turn AI adoption into sustainable operational value, according to Perforce Software's 2026 Platform Engineering Report. By Craig Risi
科技前沿
Purple Carrot Meal Kit Review: Tastier Than Meal Kits With Meat
I’m an omnivore. Purple Carrot’s vegan meal kit offers some of the best cooking I’ve seen from any meal kit, with or without meat.
开发者
The Day I Became a Bug Hunter
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. Did anyone ask for...
AI 资讯
Why I’m Writing Junior to Engineer
Hi, I’m Hélène. I’ve had computers in my life for more than forty years now, which still surprises me when I say it out loud. I started out as an eight-year-old kid playing simple games on a family computer, before the NES, before “PC gaming” was really a thing. We loaded games from cassette tapes, listened to modems sing their weird little songs, and waited for desktop machines to slowly grind their way through a boot sequence. I taught myself to program as a teenager because I wanted to make the computer do more than just play those games. Later, I went through technical school, then university, and graduated with a Computer Science degree. I did a Master-level short program in project management. I worked as a software developer for years, and now I lead a team. Along the way I read piles of books, watched improv and theatre, devoured Choose Your Own Adventure stories — only to realize much later that all of that was quiet leadership training in disguise. But there was one book I never found: the one that explained how to grow from junior to a trusted, impactful developer in a way that felt honest and practical. Not just “write clean code” or “communicate better,” but how to actually do those things, day after day, with real people, real constraints, and real doubts in your head. When I started my career, there were textbooks on algorithms and operating systems. There were tutorials on whatever language was hot that year. There were business books full of buzzwords. What I couldn’t find was the in-between book: something written by a practicing software developer, talking to another developer, about the messy, human parts of this job. Junior to Engineer is my attempt to write that missing book. Who this book is for If you’re a junior or intermediate software developer and you’re wondering things like: “How do I become the person people trust with the hard problems?” “What should I actually focus on in the first 5–10 years of my career?” “Why does everyone else se
AI 资讯
Agent-Reach absorbed Bilibili's 412s — your agent kept working
Bilibili's 412 Incident, Explained: How v1.5.0 Absorbed It In June 2026, Bilibili quietly began rejecting yt-dlp with HTTP 412 errors. Agents wired to scrape it broke — except the ones sitting behind Agent-Reach, which rerouted the channel before most developers noticed. Agent-Reach is a local, MIT-licensed capability layer that gives shell-capable coding agents live internet access by selecting and routing to upstream CLIs rather than proxying data itself . When Bilibili started 412-blocking yt-dlp in June 2026, v1.5.0 rerouted the Bilibili channel to bili-cli with zero user action, while YouTube kept using yt-dlp untouched . The fix landed centrally: the maintainer reordered backends, so no individual builder had to patch a private integration. Quick Answer: When Bilibili began returning HTTP 412 to yt-dlp in June 2026, Agent-Reach v1.5.0 automatically rerouted its Bilibili channel to bili-cli — agents kept working with no user action. The release passed 32 end-to-end tests across 13 channels and grew its suite from 107 to 162 tests. The framing shift matters: v1.5.0 describes itself as a capability layer, not a tool collection. Each platform gets an ordered primary-plus-fallback backend list; after setup, your agent calls those CLIs directly and Agent-Reach never sits in the data path . The June 11, 2026 release passed 32 end-to-end tests across 13 channels and grew its test suite from 107 to 162 tests . Platform Primary backend Fallback Web pages Jina Reader — YouTube yt-dlp — GitHub gh CLI — RSS feedparser — Bilibili bili-cli OpenCLI (subtitles) Twitter/X twitter-cli OpenCLI Reddit OpenCLI rdt-cli XiaoHongShu OpenCLI xhs-cli LinkedIn linkedin-mcp Jina Reader Global search Exa via mcporter — "capability layer: multi-backend routing + real doctor + OpenCLI" — Agent-Reach v1.5.0 release framing (source: Agent-Reach CLAUDE.md ). The behavior is easy to model. The following minimal snippet — which was executed and returns exit 0 — illustrates the "absorb and keep wo
AI 资讯
The LLM was better at building a solver than playing the game
I started this project because an LLM annoyed me. I gave a very strong model 322 , a small Dota 2 drafting game. The choices looked like the kind of work a computer should enjoy: repeated packs of players and heroes, visible ratings, familiarity scores, chemistry, rerolls and a simulated tournament at the end. I was disappointed by how well the LLM did. I am not a Dota expert, and I had only started watching it occasionally again during the previous six months or year. I still seemed to be doing better. The interesting engineering question was not how to write a longer prompt. It was how to replace the card-by-card language-model judgement with a deterministic policy, then test that policy without confusing improvement with luck. A stochastic benchmark needs shared randomness The browser history gave us a useful irritation and almost no reliable comparison. My earlier manual record contained 50 runs with a 14% title rate. The LLM won once in nine attempts. Putting 14% beside 11% looks temptingly quantitative, but the random offers, rejected packs and opponent fields were not preserved. The samples were small, unpaired and produced under different choices. That is not a model benchmark. It is a reason to build one. The offline solver generated every random choice from indexed tapes. Policy A and policy B received the same player offers, hero samples, field candidates and tournament randomness for a given episode. We could then compare the paired result: did the new policy win this exact episode where the old policy lost it? This is the common-random-numbers idea in a practical form. Sharing the luck removes a large amount of noise that has nothing to do with the policy change. Keep the simulator separate from the policy Before evaluating a strategy, we reproduced the game. The public client and seven data files were frozen with SHA-256 hashes. Draft legality, automatic hero allocation, chemistry, scoring and the tournament were ported into a deterministic Python engi
AI 资讯
ElevenLabs Expands ElevenAgents With Spotlight for Enterprise Agent Optimization
ElevenLabs has expanded ElevenAgents into a broader enterprise automation platform built around the full lifecycle of an AI agent: defining workflow-driven behavior, testing changes, deploying across customer channels, and improving performance in production. The most recent addition, ElevenAgents Spotlight , monitors voice and chat conversations in real time and provides recommendations intended to help teams improve agent outcomes. In its official ElevenAgents Spotlight announcement , ElevenLabs describes Spotlight as an observation and improvement layer for production agents . It is designed to review every conversation, organize interactions by topic, evaluate quality against criteria written in plain language, and surface context-aware suggestions. Combined with Procedures, Experiments, and Versioning, the release set gives enterprises a more structured way to operate AI agents beyond initial deployment. Spotlight adds continuous production feedback Spotlight is aimed at a common operational problem with customer-facing AI agents: a system can appear ready in testing but encounter unexpected patterns, failure modes, or shifts in customer sentiment after it reaches live traffic. Rather than requiring teams to manually sample conversations, Spotlight analyzes production voice and chat interactions as they occur. The platform can automatically group conversations by topic and track metrics including success rate and sentiment . Teams can define evaluations in plain language to score the quality of interactions against their own standards. That matters because a useful agent evaluation may depend on a company's specific process, such as whether the agent followed an escalation policy or collected required information, rather than a single generic measure of response quality. Spotlight also includes anomaly detection for changes in key metrics. Its integration support for observability tools such as Datadog, Grafana, and OpenTelemetry means the agent data can fit in
AI 资讯
What If Agent Tasks Were Installable Packages?
Coding agents can now inspect repositories, write tests, configure CI, migrate frameworks, and fix bugs. But the workflows we give them are often surprisingly informal. We copy prompts from old conversations, internal documents, GitHub issues, or random text files. Then we modify those prompts for the current project and hope we did not remove an important instruction. That made me wonder: What if a coding-agent task could be installed, inspected, versioned, and executed like a package? I built Clawx to explore that idea. 🔗 View Clawx on GitHub What is Clawx? Clawx is an open-source package manager for reusable coding-agent tasks. A package is a Markdown file with YAML metadata. The Markdown contains the instructions for the coding agent. The metadata describes information such as: The package name and version Required parameters Environment variables Dependencies Requested tools Supported agent providers A basic workflow looks like this: clawx search gitignore clawx info gitignore-gen clawx run gitignore-gen Before running the task, Clawx lets the user inspect what the package contains and which capabilities it may require. After execution, the run is recorded: clawx history The goal is to make agent workflows easier to discover, review, reuse, and audit. The problem with reusable prompts Saving useful prompts is already a good practice. But a text file containing a prompt usually does not answer questions such as: Which version am I running? Has the content changed? Which tools could the agent use? Which inputs are required? Does another task need to run first? What was executed last time? Can another developer reproduce this workflow? A prompt often contains the task, but not the operational structure around the task. Clawx treats agent instructions as versioned artifacts rather than disposable chat messages. What does a package look like? A simplified Clawx package could look like this: --- name : repo-health-check version : 1.0.0 description : " Analyze a repos
AI 资讯
React 19's useOptimistic Fixed My Instant UI. Then Combining It With useActionState Broke My Reset Button
Part 1 was about waiting well. This one is about not waiting at all, and about a couple of mistakes I...
AI 资讯
eslint-rspack-plugin 5.0.0 Ships as a Pure ESM Package, Aligning with the Rstack Ecosystem
Version 5.0.0 of eslint-rspack-plugin has been released as a pure ESM package, aligning with the Rspack ecosystem and removing its CommonJS build. The plugin continues to integrate ESLint in the build process but may affect build times. Users are advised to consider separate linting commands for efficiency. The project is open source and available via npm. By Daniel Curtis
AI 资讯
SQLazy:Merge Multiple Tables into Single Rows by Common ID
Problem Description Merge multiple structurally similar tables with different column names into a wide table using full outer joins by common ID. Four tables have similar structures, each with two fields. The fields have the same meaning but different names (id, id2, id3, id4 all represent ID). The goal is to merge the four tables into single rows by ID, with each ID appearing in exactly one row. When an ID is absent in a table, the corresponding columns take NULL. Source Data T1 table: T2 table: T3 table: T4 table: * Expected Result * For example, ID=555 appears in both T1 and T2 but not in T3 or T4, so id, colA, id2, colB have values, while id3/colC/id4/colD are NULL. ID=222 only appears in T3, so only id3 and colC have values; all other columns are NULL. ID=10 appears in T2 and T4 but not in T1 or T3, so id2, colB, id4, colD have values; all other columns are NULL. SQLazy Step-by-Step Implementation Core Idea: First use derive to unify the ID column names of each table to ID_main, making subsequent merging easier. Then start from the first table and perform full outer joins one by one: use join to full outer join the current result with the next table on ID_main, then use derive and nvl to merge the new ID into the ID_main column, appending tables one by one to get the final result. [ Click to run this example online ] The steps are explained below. Steps 1-4: Unify ID Column Names Across Tables derive id as ID_main, id, colA Use derive on T1-T4 to rename their respective ID column names (id/id2/id3/id4) uniformly to ID_main. Step 5: Full Outer Join T1 and T2 join ID_main; with t2; ID_main; take id2, colB; full Use the join function to full outer join t1 and t2 on ID_main. Step 6: Merge NULLs in ID Column derive nvl(ID_main, id2) as ID_main, id, colA, id2, colB If a record comes from t2 but is not present in t1, its ID_main is NULL. This step assigns t2.id2 to ID_main in such records, ensuring the ID_main column always has a value. Different SQL implementations u
AI 资讯
Swarm of OpenAI Agents Exploit Artifactory Zero-Day to Escape Sandbox and Breach Hugging Face
Security disclosures highlighted vulnerabilities in AI evaluations of autonomous cyber capabilities. Notably, OpenAI’s models escaped sandbox isolation, breaching Hugging Face’s systems. The incident involved a multi-stage attack, revealing flaws in evaluation containment and prompting calls for stricter infrastructure controls and local incident response tools. By Olimpiu Pop
AI 资讯
AWS Introduction for Beginner Software Engineers
As a software engineer starting with AWS, you might feel overwhelmed by all the services. Let me break down the key components with real-world examples to help you get started. 1. DNS & How AWS Route 53 Works Problem: Users can't remember IP addresses like 54.210.167.101 for your app. Solution: AWS Route 53 (DNS service) maps yourdomain.com to your servers. Real example: Your startup has servers in Ohio and Frankfurt. Route 53 automatically sends European users to Frankfurt and routes US traffic to Ohio — faster load times for everyone. 2. Networking: VPC & Subnets VPC: Your private cloud network (like an office building). Public subnet: For web servers (needs internet access). Private subnet: For databases (blocked from direct internet access). Internet Gateway: Connects public subnets to the internet. NAT Gateway: Lets private subnets reach the internet (one-way). Real example: In your e-commerce app, the web server runs in a public subnet while the database sits in a private subnet. 3. Storing & Delivering Static Files (S3 + CloudFront) Amazon S3: Stores images, videos, and logs. CloudFront (CDN): Caches content globally for faster loading. Real example: Your blog hosts images in S3; CloudFront caches them in 450+ locations, so a reader in Tokyo gets images from Japan instead of Virginia — cutting load time by ~50%. Pro tip: Enable S3 Versioning to recover accidentally deleted files. 4. Running Backend Services AWS Lambda (Serverless) — best for event-driven tasks. Example: a photo app resizes images automatically on upload. EC2 (Virtual Servers) — best for full control (custom OS, legacy apps). Example: hosting a Java monolith with specific dependencies. ECS/EKS (Containers) — best for microservices (Docker/Kubernetes). Example: a food-delivery app with separate services for orders, payments, and tracking. 5. Databases: Picking the Right One Amazon RDS (SQL): Structured data with relationships — e.g. user accounts + orders. DynamoDB (NoSQL): High-speed, scalable
AI 资讯
TypeScript `asserts` and Type Predicates in 2026: Writing Guards That Actually Narrow Correctly
TypeScript asserts and Type Predicates in 2026: Writing Guards That Actually Narrow Correctly This article was written with the assistance of AI, under human supervision and review. Most TypeScript runtime validation breaks down because engineers write guards that compile but don't actually narrow types where it matters. The pattern that teams overlook is the distinction between type predicates that return boolean values and assertion functions that throw on failure—and choosing the wrong one creates silent bugs that surface in production. The problem starts when developers write a function like isUser(value: unknown): boolean and expect TypeScript to understand what that boolean means. The compiler sees the function return true but has no idea that value is now safe to treat as a User type. Code that looks validated crashes at runtime because the type system never learned what the validation actually proved. The fix is adding the type predicate syntax value is User to the return signature. This tells TypeScript that when the function returns true , the narrowed type holds in the calling scope. For throwing guards that never return on failure, the asserts keyword encodes that guarantee into the signature itself. That distinction is critical. Type predicates return booleans and enable conditional narrowing. Assertion functions throw errors and narrow the remainder of the scope unconditionally. Mixing them up or using neither creates validation theater—code that runs checks but provides zero type safety. Key Takeaways Type predicates ( value is Type ) narrow types conditionally when the guard returns true , while assertion functions ( asserts value is Type ) narrow unconditionally by throwing on failure. Most guard functions fail to narrow because they return boolean instead of using predicate syntax—the compiler cannot infer type information from a plain boolean. Assertion functions are superior for null checks and invariants that should never fail, while type predic
AI 资讯
Linux Troubleshooting Workflow for Beginners: A Step-by-Step Guide
Most Linux problems aren't actually difficult. They're difficult because they're often debugged in the wrong order. Many beginners immediately: Restart services randomly Run commands without a plan Change configurations before understanding the problem Guess instead of observing Experienced engineers do something different. They follow a structured troubleshooting process. This article isn't about learning new Linux commands. It's about knowing when and why to use the commands you've already learned throughout this Linux Beginner Series. Think of it as putting everything together into one practical troubleshooting workflow that's used in real Linux and DevOps environments. Quick Troubleshooting Workflow Observe ↓ Check System Health ↓ Identify Problem Type ↓ Read Logs ↓ Verify Service ↓ Check Network ↓ Check Disk ↓ Recent Changes ↓ Find the Root Cause ↓ Apply the Fix Keep this workflow in mind as you read through the guide. Step 0: Observe Before You Change Anything Before running a single command, pause for a moment. Ask yourself: What exactly is broken? When did the issue start? Is everyone affected or only some users? Is the problem constant or intermittent? What changed recently? Many troubleshooting sessions become longer because people try to fix the problem before they understand it. Good troubleshooting begins with observation, not commands. Step 1: Check Overall System Health Your first goal is to understand the overall health of the system—not to fix anything yet. Useful commands: uptime free -h top Look for: High load average High CPU usage Low available memory Signs that the server is under heavy load At this stage, you're only gathering evidence. A quick system health check often tells you where to investigate next. Step 2: Identify the Type of Problem Before diving deeper, classify the issue. Problem Type Common Symptoms First Commands to Check CPU Slow system, high CPU usage top , htop Memory Applications crashing, OOM kills free -h Disk "No space lef
开发者
Stop hls.js from flapping between quality levels on cellular (with abrSwitchInterval)
TL;DR ABR "flapping" is when your player hops between quality levels every few seconds on a jittery network, and each hop is a visible lurch. We'll detect it from LEVEL_SWITCHED events, then fix it in layers: widen the bandwidth-estimator memory, make upswitches earn their place, and cap the switch rate with abrSwitchInterval (new in hls.js 1.7). Config + a detection snippet you can paste in today. 📦 Code: github.com/USER/hlsjs-abr-tuning, replace before publishing The bug nobody reports correctly Users don't file "my ABR is flapping." They say the video "kept changing" or "couldn't decide." What's happening: on cellular, throughput is spiky, and the player's bandwidth estimator treats every spike as the new truth. One fast segment and it jumps to 1080p, one slow segment and it drops to 240p, over and over. Low rebuffer ratio, good startup time, and still a miserable watch. Counterintuitively, feeding the player fresher bandwidth data makes this worse, because fresher data is noisier. The fix is a player with a longer memory and slower reflexes. Let's build that. 1. First, detect the flap 📊 Don't tune by vibes. Count level switches per minute of playback. Every switch fires Hls.Events.LEVEL_SWITCHED . // abr-monitor.js, hls.js 1.7.x, node 20+ tooling / any modern browser import Hls from " hls.js " ; export function attachFlapMonitor ( hls ) { const switches = []; hls . on ( Hls . Events . LEVEL_SWITCHED , ( _evt , data ) => { const now = performance . now (); switches . push ({ t : now , level : data . level }); // keep a 60s sliding window while ( switches . length && now - switches [ 0 ]. t > 60 _000 ) switches . shift (); const perMin = switches . length ; const reversals = countReversals ( switches ); if ( perMin >= 6 ) { console . warn ( `[abr] flapping: ${ perMin } switches/min, ${ reversals } reversals` ); } }); } // a "reversal" = up then down (or down then up), the signature of flapping function countReversals ( s ) { let r = 0 ; for ( let i = 2 ; i < s . l
AI 资讯
Architecture Decisions Before Writing a Single Line
The most valuable thing Claude has done for my work is help me make better architectural decisions before I start building. When I was designing my hotel reservation system I needed to handle multi-currency pricing and timezone conversion. My first instinct was to put all of that logic directly in the booking controller alongside the reservation code. It would have worked but it would have created a mess that was hard to test and harder to extend. Before writing anything I described the problem to Claude and talked through a few approaches. The conversation helped me see that separating pricing and timezone logic into dedicated service classes would make each piece independently testable and easier to swap out later. The booking controller would just call those services without knowing how they worked internally. That conversation took maybe twenty minutes. It saved me hours of refactoring later. I still designed the system. I still made the judgment calls. But the quality of my thinking going into implementation was significantly better because I had a thinking partner to pressure test my ideas against.
AI 资讯
I built a tool that roasts your code with regex — no AI involved
The problem In 2026, devs spend 11.4 hours a week reviewing AI-generated code — more time than they spend writing it. We're burning cycles fixing bugs our own AI tools wrote. I started calling this "AI debt": the maintainability tax that piles up when nobody's actually reading the code the assistant just spat out. I wanted a fast, brutal way to see how much debt was hiding in a file before I even opened a PR. What I built Roast My Code — paste a code snippet, get an AI Debt Score (0–100) and get roasted for your sins. 118 regex patterns across 8 languages (JS/TS, Python, Go, Rust, Java, PHP, C++) Scores broken into Readability, Structure, Error Handling, Safety, and Style Code metrics: nesting depth, duplication %, comment ratio, avg line length Three brutal one-liner roasts + concrete fixes for each issue found The twist: zero AI. No API calls, no LLM, no backend. Everything runs client-side with regex pattern matching. Your code never leaves your browser. Why regex, not AI Honestly — irony. A tool built to call out AI slop shouldn't itself be another wrapper around GPT. Regex is also just... faster. No API latency, no cost, no rate limits, no "please wait while I analyze your code" spinner. You paste, you get roasted in under a second. It's not going to catch everything a proper linter or an LLM code reviewer would. That's not the point — it's a gut-check, not a static analysis suite. A taste of the roasts javascript var API_KEY = "sk_live_51H8xJ2kL9mNpQrStUvWxYz..."; if (a == 1) { if (b == 2) { if (c == 3) { x = eval(a + b + c); } } } 🔒 is that a hardcoded credential? in 2026? we need to talk. your teammate rewrote this on a Sunday. FIX: Move it to an environment variable or secret store, then rotate the credential. 🎆 eval(). we don't need to say more. you know what you did. this is the part reviewers skim past. FIX: Replace eval with a lookup table, JSON.parse, or an explicit parser. Try it 🔗 Live app 💻 Source on GitHub — MIT licensed, PRs welcome Paste your wor
AI 资讯
Decision Trees Aren't Trained. They're Grown.
Classic Machine Learning Through the Eyes of an SRE — Part 2 The second algorithm I studied broke everything I'd just learned from the first. Logistic regression taught me that training means gradient descent: guess, measure error, adjust the weights, repeat until convergence. So when I opened decision trees, I went looking for the optimizer. There wasn't one. A decision tree isn't optimized the way I expected. It's grown. At each step it finds the locally best split, commits to it, and recursively repeats the process. No backtracking. No second chances. There is optimization happening — each split minimizes impurity — but only locally, one step at a time. Finding the globally optimal tree is NP-hard, so the algorithm doesn't even try. That felt surprisingly familiar. In incident response or capacity planning, we rarely know the perfect answer. We make the best decision with the information we have, knowing a different first choice might have led somewhere else. Decision trees simply turn that idea into an algorithm. The bet a tree makes Every machine learning algorithm makes a different bet about the world. Logistic regression assumes relationships are smooth. Risk gradually increases as signals change. Decision trees make the opposite assumption. They assume the world is made of boxes. A project isn't slightly riskier because velocity drops. It's risky when several conditions happen together: a fixed-price contract, a new account manager, and a month-end delivery. Inside that box, projects fail. Outside it, they're usually fine. This is exactly how many operational systems work. Severity matrices, routing rules, escalation policies, approval workflows — they're all collections of decision boxes. That's why trees immediately felt intuitive to me. The hidden cost of flexibility Trees make very few assumptions about the data. That sounds like an advantage. The price is instability. Change a small part of the training data and the first split can change. Since every l