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

Same Edge, Same Experience: Ghostery Brings Desktop Ad Blocking to Your iPhone and Android

1 Share
https://images.prismic.io/ghostery/aMKCumGNHVfTPB8o_Ghostery-Android-iphone-Edge-thumbnail.png?auto=format,compress
Read the whole story
alvinashcraft
17 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Sam Altman is hiring someone to worry about the dangers of AI

1 Share
ISO corporate scapegoat.

OpenAI is hiring a Head of Preparedness. Or, in other words, someone whose primary job is to think about all the ways AI could go horribly, horribly wrong. In a post on X, Sam Altman announced the position by acknowledging that the rapid improvement of AI models poses "some real challenges." The post goes on to specifically call out the potential impact on people's mental health and the dangers of AI-powered cybersecurity weapons.

The job listing says the person in the role would be responsible for:

"Tracking and preparing for frontier capabilities that create new risks of severe harm. You will be the directly responsible leader for bui …

Read the full story at The Verge.

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

The 3 a.m. Call That Changed The Way I Design APIs

1 Share
Sleeping man answering a phone call.

At 3:17 a.m. on a Tuesday, my phone buzzed with the alert that would reshape the way I think about API design.

Our customer-facing API had stopped responding. Not slowly degrading; it was completely dead. Three downstream services went with it. By the time I got to my laptop, customer support tickets were flooding in.

The root cause? A single database replica had gone down, and our API had no fallback. One failure cascaded into total unavailability. I spent the next four hours manually rerouting traffic while our customers waited.

That night cost us $14,000 in service-level agreement (SLA) credits and a lot of trust. But it taught me something I now apply to every API I build: Every design decision should pass what I call “The 3 a.m. Test.”

The 3 a.m. Test

The test is simple: When this system breaks at 3 a.m., will the on-call engineer be able to diagnose and fix it quickly?

This single question has eliminated a surprising number of “clever” design choices from my architectures:

  • Clever error codes that require documentation lookup? Fail.
  • Implicit state that depends on previous requests? Fail.
  • Cascading failures that take down unrelated features? Fail.

After that incident, I rebuilt our API infrastructure from the ground up. Over the next three years, handling 50 million daily requests, I developed five principles that transformed our reliability from 99.2% to 99.95% and let me sleep through the night.

Principle 1: Design for Partial Failure

Six months after the initial incident, we had another outage. This time, a downstream payment processor went unresponsive. Our API dutifully waited for responses that never came, and request threads piled up until we crashed.

I realized we’d solved one problem but created another. We needed systems that degraded gracefully instead of failing catastrophically.

Here’s what we built:

class ResilientServiceClient:
    def __init__(self, primary_url, fallback_url):
        self.primary = primary_url
        self.fallback = fallback_url
        self.circuit_breaker = CircuitBreaker(
            failure_threshold=5,
            recovery_timeout=30
        )
    
    async def fetch(self, request):
        # Try primary with circuit breaker protection
        if self.circuit_breaker.is_closed():
            try:
                response = await self.call_with_timeout(
                    self.primary, request, timeout_ms=500
                )
                self.circuit_breaker.record_success()
                return response
            except (TimeoutError, ConnectionError):
                self.circuit_breaker.record_failure()
        
        # Fall back to secondary
        try:
            return await self.call_with_timeout(
                self.fallback, request, timeout_ms=1000
            )
        except Exception:
            # Return degraded response rather than error
            return self.degraded_response(request)


The key insight: A degraded response is almost always better than an error. Users can work with stale data or reduced functionality. They can’t work with a 500 error.

After implementing this pattern across our services, we stopped having cascading failures. When the payment processor went down again (it did, three more times that year), our API returned cached pricing and queued transactions for later processing. Customers barely noticed.

Principle 2: Make Idempotency Non-Negotiable

This lesson came from a $27,000 mistake.

A mobile client had a bug that caused it to retry failed requests aggressively. One of those requests was a payment. The retry logic didn’t include idempotency keys. You can guess what happened next.

A single customer got charged 23 times for the same order. By the time we noticed, we’d processed duplicate charges across hundreds of accounts. The refunds, the customer service hours, the engineering time to fix it cost $27,000.

Now, every mutating endpoint requires an idempotency key. No exceptions.

class IdempotentEndpoint:
    def __init__(self):
        self.idempotency_store = RedisStore(ttl_hours=24)
    
    async def handle_request(self, request, idempotency_key):
        # Check if we've already processed this request
        existing = await self.idempotency_store.get(idempotency_key)
        
        if existing:
            # Return cached response — don't re-execute
            return Response(
                data=existing['response'],
                headers={'X-Idempotent-Replay': 'true'}
            )
        
        # Process the request
        result = await self.execute_operation(request)
        
        # Cache for future retries
        await self.idempotency_store.set(
            idempotency_key,
            {'response': result, 'timestamp': now()}
        )
        
        return Response(data=result)


We also started rejecting requests without idempotency keys for any POST, PUT or DELETE operation. Some client developers complained initially. Then they thanked us when their retry bugs didn’t cause data corruption.

Principle 3: Version in the URL, Not the Header

I learned this one by watching a junior engineer debug an issue for six hours.

We’d been versioning our API through a custom header: X-API-Version: 2. It seemed clean. Kept the URLs tidy.

But when something went wrong, our logs showed the URL and response code — not the headers. The engineer was looking at logs for /users/123 and couldn’t figure out why the behavior was different between two clients. Six hours later, he finally thought to check the version header.

We moved versioning to the URL path that week:

/v1/users/123
/v2/users/123


Now version information shows up in:

  • Every log entry
  • Every trace
  • Every error report
  • Every monitoring dashboard

The debugging time savings alone justified the migration. But we also established versioning rules that prevented future pain:

  • Breaking changes require a new version
  • Additive changes (new optional fields) don’t require a new version
  • We support at least two versions simultaneously
  • 12-month deprecation notice before sunsetting any version

When we do deprecate a version, clients get a Deprecation header warning them for months before we actually turn it off.

Principle 4: Rate Limit Before You Need To

We almost learned this lesson the hard way.

A partner company integrated with our API. Their team’s implementation had a bug: When they got a timeout, they’d retry immediately. Infinitely. With exponential parallelism.

At 2 p.m. on a Thursday, their system started sending 50,000 requests per second. We didn’t have rate limiting. We’d always planned to add it “when we needed it.”

We needed it.

Fortunately, our load balancer had basic protection that kicked in and started dropping requests. But legitimate traffic got dropped too. For 47 minutes, our API was essentially a lottery — maybe your request would get through, maybe it wouldn’t.

The next week, we implemented tiered rate limiting:

class TieredRateLimiter:
    def __init__(self):
        self.limiters = {
            'per_client': TokenBucket(rate=100, burst=200),
            'per_endpoint': TokenBucket(rate=1000, burst=2000),
            'global': TokenBucket(rate=10000, burst=15000)
        }
    
    async def check_limit(self, client_id, endpoint):
        # Check all tiers, return first failure
        for tier_name, limiter in self.limiters.items():
            key = client_id if tier_name == 'per_client' else endpoint
            result = await limiter.check(key)
            
            if not result.allowed:
                return RateLimitResponse(
                    allowed=False,
                    retry_after=result.retry_after,
                    limit_type=tier_name
                )
        
        return RateLimitResponse(allowed=True)


The key details that made this actually useful:

  • Always return Retry-After headers so clients know when to try again.
  • Include X-RateLimit-Remaining so clients can see their budget.
  • Use different limits for different client tiers (partners get more than anonymous users).
  • Separate limits per endpoint (the search endpoint can handle more than the payment endpoint).

That partner’s bug happened again six months later. This time, their requests got rate-limited, our other clients were unaffected, and I didn’t even find out until I checked the metrics the next morning.

Principle 5: If You Can’t See It, You Can’t Fix It

The scariest outages aren’t the ones where everything breaks. They’re the ones where something is subtly wrong and you don’t notice for days.

We had an issue where 3% of requests were failing with a specific error code. Not enough to trigger our availability alerts (we’d set those at 5%). Not enough for customers to flood support. But enough that hundreds of users per day were having a bad experience.

It took us two weeks to notice. Two weeks of a broken experience for real users.

After that, we built observability into every endpoint:

class ObservableEndpoint:
    async def handle(self, request):
        trace_id = self.tracer.start_trace()
        start_time = time.time()
        
        try:
            response = await self.process(request)
            
            # Record success metrics
            duration_ms = (time.time() - start_time) * 1000
            self.metrics.histogram('request_duration_ms', duration_ms, {
                'endpoint': request.path,
                'status': response.status
            })
            self.metrics.increment('requests_total', {
                'endpoint': request.path,
                'status': response.status
            })
            
            return response
            
        except Exception as e:
            # Record failure with context
            self.metrics.increment('requests_errors', {
                'endpoint': request.path,
                'error_type': type(e).__name__
            })
            self.logger.error('request_failed', {
                'trace_id': trace_id,
                'error': str(e)
            })
            raise


Our minimum observability requirements now:

  • Request count by endpoint, status code and client
  • Latency percentiles (p50, p95, p99) by endpoint
  • Error rate by endpoint and error type
  • Distributed tracing across service boundaries
  • Alerts at 1% error rate, not 5%

The 3% failure issue? With our new observability, we would have caught it in minutes, not weeks.

The Results

After three years of applying these principles across our API infrastructure:

Metric Before After
Monthly availability 99.2% 99.95%
Mean time to detection 45 minutes 3 minutes
Mean time to recovery 2 hours 18 minutes
Client-reported errors 340/week 23/week
3 a.m. pages (per month) 8 0.5

That last metric is the one I care about most. I went from being woken up twice a week to once every two months.

What I’d Tell My Past Self

If I could go back to before that first 3 a.m. call, I’d tell myself:

  • Build for failure from day one. Every external call will eventually fail. Every database will eventually go down. Design for it before it happens, not after.
  • Make the safe thing the easy thing. Requiring idempotency keys feels like friction until it saves you from a $27,000 mistake. Rate limiting feels unnecessary until a partner’s bug tries to take you down.
  • Invest in observability early. You can’t fix what you can’t see. The cost of good monitoring is nothing compared to the cost of not knowing your system is broken.
  • Boring is good. The clever solution that’s hard to debug at 3 a.m. isn’t clever. Version in the URL. Return clear error messages. Make the obvious choice.

APIs don’t survive by accident. They survive by design, specifically, by designing for the moment when everything goes wrong.

Now, when my phone buzzes at 3 a.m., it’s usually just spam. And that’s exactly how I like it.

The post The 3 a.m. Call That Changed The Way I Design APIs appeared first on The New Stack.

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

5 Key Trends Shaping Agentic Development in 2026

1 Share
Illustration of a box being opened and showing a star emerging from it

So far in my review of agentic development over the past year and heading into 2026, I’ve looked at some of the trends shaping LLM services. In this post, I’ll focus on what to expect for AI development tools in the new year.

As Cory Doctorow points out in his Reverse Centaur summary, tech companies always want to be “growth stocks” — and for that reason they have to continually prove there is a new vision with untapped potential. This works against teams just improving on existing offerings — heaven forbid the company’s stock is marked as “mature.” But that is really what 2026 should be about: improving on the plethora of new things that developers are trying to get to grips with.

1. Improving Visibility and Management of Model Context Protocol (MCP)

Since Model Context Protocol (MCP) has quickly become the accepted way agents interact with external tools, there will have to be more effort to keep the MCP servers under control — either with central management or clearer dashboards. While developers have enjoyed the improved workflows that connectivity brings, the management of these has been a bit ad hoc. The success of MCP seems to work across silos, as non-technical staff want their agent requests to talk to Slack, etc. These internal connections kind of answer the “whats going on in my own business?” queries. Which means developers will be busy setting up MCP servers.

If there will be a lot of active MCP servers in an organisation, then management of them will start to become more significant. The more things people find to do with MCP, the more concerns will appear.

2. Supporting Parallel Task Execution for Senior Engineers

This year I looked at two apps (Conductor and Verdent AI) that explicitly support running tasks in parallel — that is, effectively defining a task and just leaving an LLM to execute it in the background while starting a new task. While you can generally ask any Agentic CLI to run a task in the background, more apps will support parallel running as a workflow in 2026.

One thing to note about executing these: to work on the same codebase, the target code needs to be isolated. This usually means making a new branch for each task and then putting the code into a fresh folder, which is what git worktrees does. You then merge the work back into the main branch. All this git fiddling plays slightly against the “vibe coding” moniker — but as I’ve pointed out, LLM tools will always gravitate towards being most useful to senior developers.

It is also only devs with solid experience who can quickly evaluate whether a change is safe enough to entrust to an agent… or not. And it is the senior developers who are already used to interruptions throughout the day, in this case coming from agents completing tasks at different times.

3. Clarifying the Roles of Agentic CLI vs. Desktop Applications

When we first saw Claude Code running in a terminal session, it immediately got developers to define tasks in English instructions. Hence the term Agentic Command Line Interface (CLI). This was in sharp relief to using an IDE like VS Code.

Built in TypeScript and React, Claude Code ran in any terminal shell, allowing it to share an immediate environment and start in the same directory as the project to be worked on. This felt comfortable for many developers. There have been quite a few similar CLI apps released since then. The ability to also pass shell commands on the same prompt (implemented most cleanly in Warp) helped to reduce the friction of app swapping.

But many desktop versions were also released, such as Claude Desktop, which offered the advantages of UI honed on MacOS or Windows. For example, you get nice file and folder views, along with more control over the request and response UI components. From an enterprise point of view, managing a desktop app is a bit easier too. However, exactly how the desktop app compares to the CLI version can still be unclear.

In 2026, I expect all major providers to make it clearer how they will support both their CLI and desktop versions of LLM products. Each version may have different communities, but they shouldn’t be treated as separate entities.

4. Integrating Paid Services and Agent-Driven Commerce

How agents successfully request paid services — i.e. agent-driven commerce — has to pop up at some stage. There isn’t a screaming demand for this, but eventually an agent will need to call upon a paid service in the background — or use a more expensive model in a task that the caller doesn’t have an explicit payment plan for. Most of us are simultaneously suspicious and accepting of the “machine-to-machine economy.” There is no point in autonomy that has to stop at the till. There may be various attempts to start addressing this over the year; especially for products that can use multiple models. This is especially true for developers running local LLMs who only want to call cloud LLMs for the deeper tasks.

5. Addressing the Challenges of VS Code Forks in AI Development

The Microsoft Visual Studio Code forking problem has to be addressed a little more closely. We have seen quite a few non-Microsoft apps that are actually forks of VS Code under the covers — Cursor was an early example. While using the extension model within VS Code isn’t really good enough to support LLMs, forks have limitations too. The problem with finding other extensions in a less secure independent marketplace will probably remain an issue. In some respects Microsoft has successfully captured the market, leaving the competition to join or fragment. I don’t think anything broke inside me when Google launched its own VS Code fork, Antigravity, but it did bring the whole issue to a head again.

Too many product teams have seen a VS Code fork as a quick win, without ever really asking themselves if they have serious plans to buy their own home — or whether they will rent forever. Then they forget that their rental contract prevents them from hammering nails into the wall. But there are likely to be new approaches to get around this in 2026.

Conclusion

This has been the breakout year for Agentic AI tools, especially the Agentic CLI, and I would expect 2026 will be about securing that ground. Developers don’t need to be convinced about what LLMs can achieve, but they do need to be convinced that the available products can be trusted to support their workflows over time.

The post 5 Key Trends Shaping Agentic Development in 2026 appeared first on The New Stack.

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

Trends That Defined JavaScript in 2025

1 Share
Image showing a wrapped gift with a bow. Indicates "year wrapup."

The year 2025 proved to be a transformative period for the JavaScript ecosystem, marked by a shift toward performance optimization and “post-React” exploration. We look back at the stories and trends that dominated the JavaScript community in 2025.

Challenging React

While React remains a central pillar of development — even LLMs, when left to their own devices, will primarily push out React code —  in 2025, more developers called for a “web standards first” philosophy that prioritizes simplicity, as developers began to question the necessity of heavy client-side abstractions.

In part, this is because modern browsers have matured enough to handle tasks previously requiring React, including support for the View Transitions API and web components. We also saw this with Remix 3, which challenged React-centric architectures by prioritizing web fundamentals with loaders/actions over React-specific state management. It signalled that React should be the view layer, not the foundation.

But it wasn’t all bad news for React: It now has its own foundation. In a major governance shift for React, Meta moved the framework’s governance to an independent foundation under the Linux Foundation, with the goal of fostering corporate neutrality and broader ecosystem contribution.

Framework Trends: MPAs, Signals and Compilers

Frameworks didn’t slow down in 2025. In fact, the year saw new frameworks introduced — including the microframework Hono, which is used for edge computing.

There was also the React-based One, which supports the creation of create both web and native platform applications. The year also saw the release of the minimalistic Mastro, which is used for multipage apps. It champions “zero-JS by default” and enables browser-native routing instead of heavy client-side SPAs. Finally, there was Wasp, which offers a full-stack solution that creates a Ruby on Rails-like experience for the React/Node ecosystem.

When it came to non-React frameworks, Signals became a keystone of reactivity. Signals uses reactivity only for the exact part of the UI that is updated. Angular, Vue, Solid and Svelte all now use Signals for state management. There’s even a push to add Signals to the JavaScript specifications.

But moving forward into 2026, Ryan Carniato, creator of SolidJS, predicted that fine-grained reactivity may be the next frontier for non-React frameworks.

“It’s hard to ignore the impact when pretty much every framework other than React has adopted Signals first-class at this point,” he said, adding that “we’re just at the beginning of a much bigger change, and I’m not alone in this thinking.”

We also saw a focus on fine-grained reactivity with Runes in Svelte 5, which was released in late 2024.

Compilers are also taking on more heavy lifting. Svelte 5’s Runes, which were released as stable at the end of 2024, rely on Svelte’s compiler. The compiler transforms Runes, which look like functions, into a Signals runtime. The React Compiler also was marked as stable this year. React uses the compiler to automate memoization, which is a term for changing how much of the UI re-renders, as opposed to changing how the data updates (which is what the Svelte compiler does).

In both cases, though, the compiler is doing some of the heavy lifting of transforming”human-readable” code into optimized machine code to avoid unnecessary re-renders.

Tooling: The Battle for a Unified Stack

At the end of 2024, Vite creator Evan You announced VoidZero, a company dedicated to creating a unified Rust-based toolchain for the web development community. This ecosystem of tools would finally address the “fragmentation tax” of JavaScript development — where developers “duct-tape” together dozens of tools.

TNS Senior Editor Richard MacManus spoke with You about the resulting unified toolchain, Vite+, in October. “Vite+ is a unified layer that put all these things together under one coherent solution, right? So it is a drop-in superset of Vite itself,” You said.

It bundles several different open source projects You’s company is working on, including:

  • Rolldown, a new Rust-based bundler for Vite;
  • Oxlint, a Rust-powered linter for JavaScript and TypeScript;
  • Vitest, a Vite-native testing framework; and
  • Oxc, a collection of JavaScript tools written in Rust.

AI and Frameworks

AI moved from the backend to the frontend in 2025. We saw a host of MCP servers launched to help frameworks connect best practices and standards with AI, including MCP servers from Angular and React, with more planned by frameworks such as TanStack Start.

Framework maintainers like Minko Gechev even experimented with an “LLM-first” framework designed specifically to be easily written and debugged by AI agents. TanStack recently released TanStack AI, an alpha release of a new framework-agnostic AI toolkit for developers.

We’ve also seen a shift to using AI within the browser, with libraries like AsterMind-ELM and TensorFlow.js allowing developers to train and run machine learning models directly in the browser with microsecond latency, bypassing the need for expensive server-side GPUs. There’s also Hashbrown, an open source framework that lets AI agents run in the browser.

Looking Ahead to 2026

The year 2025 led to JavaScript progress in surprising ways, but perhaps leaves more questions than it answered. Will frameworks finally be pushed to converge? Will more frameworks be launched in 2026 to address new concerns and needs? What will AI mean for JavaScript and the ecosystem that supports it?

Hopefully, in the coming year, we’ll get answers to those questions.

The post Trends That Defined JavaScript in 2025 appeared first on The New Stack.

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

Random.Code() - Advent of Code 2025 Playthrough - Part 6

1 Share
From: Jason Bock
Duration: 1:45:24
Views: 32

I think I know where I messed up with Part 1 of Day 8, so hopefully I can solve it in this stream and move on to get more stars!

https://adventofcode.com/2025
https://github.com/JasonBock/AdventOfCode2025

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