Latest Posts (20 found)

book: bad blood by john carreyrou

I finished Bad Blood recently :) It is a must-read if you want to understand what happened with Elizabeth Holmes and Theranos. It is very specific and focused in that regard - it isn't a general observation about Silicon Valley or Palo Alto startups with her as an example (which parts of the cover may suggest), but instead a detailed recount and look behind the scenes by the journalist who broke the initial story. It feels like a written documentary as much as it feels like a piece of evidence, a permanent record of everything, especially Carreyrou's diligent work. It has exactly the tone of something you'd write after dedicating almost your entire life to that case for about 3 years and then writing everything down in case it ever becomes relevant again, in case people forget once she gets out, or in case anyone would ever decide to come for you. An insurance one can always point to about the exact work, timeline and details. This extreme involvement and expertise really helps flesh out the case and explains a lot of the background workings without relying on potentially more unreliable secondhand sources, but it also made it hard for me to keep all the less important characters apart, especially in the beginning. There's a flurry of characters being set up in the beginning that are not really relevant for much longer and they aren't given the space and details to become fleshed out people you can actually remember and differentiate between. Pages full of sentences filled to the brim with random names and their connections and investments that may almost never be mentioned again for the rest of the book. Later on, their last or first name may come up again, but because they were just introduced briefly 50+ pages prior and their only characteristic was investing this amount or coming from that company, you don't even know who that was anymore; same with the first few employees, I'd say. I understand they are needed for the evidence and bigger picture, but it made getting into the book a bit difficult because you are bombarded with names without anything substantial to tie them to or having an idea how relevant they'll be to the case. It's absolutely understandable that this "blindness" to how much introduction and explanation a person involved in the scandal needs for the average layperson exists when you've been so deep into the story for years that it just seems obvious to you. It isn't always like this: Sometimes, out of nowhere, at what felt like the wrong time for me, the reader suddenly got a glimpse of someone's personality for no apparent reason. It'd be some tense negotiation or argument and we'd suddenly be treated to something akin to " [Name], who likes his tea black, said he had never heard of this machine before ." (not a quote, but a close example, because I currently cannot find the examples I was thinking of). Why am I suddenly out of nowhere being told this, when it has not been relevant in this situation? At other times, especially much later in the book, the vivid details really spill out of Carreyrou. It almost turns into a fiction novel the way the scenery, clothes and demeanours are described, which can definitely be enjoyable and break up the matter-of-fact tone of this non-fiction, but also felt a little much in some occasions; so much so that, if I hadn't known this was all real and neither non-fiction nor fiction based on real events, I'd have wondered if this is where things stray into fiction, as this level of detail is usually reserved for that. As the book goes on, the pacing becomes faster and faster. The closer we get to the core of it, the house of cards falling apart, the more things happen at once, new twists and turns emerge, and the more erratic and threatening the behavior of people involved becomes. The ending is rather anti-climactic. Suddenly, it all stops. We have read this insanity, and then there is no resolution, no closure, no punishment. It is in the hands of the court now and we'll have to see what happens. Nowadays, of course we know what happened, but I am a little sad the book had to stop where it did, as it was released in 2018. At least there's a podcast for the book by Carreyrou that also covers the trial, but I still wish there could have been an update to the book (aside from the 2020 Afterword, when the sentencing was in 2023), though I imagine the author also wants to reclaim his life and not keep having to go back to this, or at least get to take a longer break away from it. I hope maybe he'll keep his eyes peeled on what's happening with Haemanthus in the future :) Published 27 Sep, 2026

0 views
Unsung Today

“I’m especially proud of the 1e+9 duration.”

I liked this post by Roel Nieskens , about ten lines of code that, one way or another, mean something to me. Either because I wrote them, or I extensively copied them, or they made me laugh. Or cry. It’s perhaps a different take on cursed knowledge , and made me wonder what those would be for me, or for other people with different specializations. (We previously talked about Duff’s device , which had a certain impact on me – even though I never used it myself.)

0 views
Unsung Today

“First, don’t interfere with user input.”

In response to a previous post , one of the readers wrote this: I would phrase this as the fault of the animation having violated the Hippocratic oath for animations, which is “first, do no harm” a.k.a. “first, don’t interfere with user input”. Yes, one has to be afraid of hyperbole – was there ever an onscreen transition that saved a life? – but there is something I really liked about this phrasing. After all, most transitions and animations are decorators, and every transition and animation is, by definition, also a delay . Here’s Shazam as I open it, and overlaid are my frantic taps as I’m trying to make it start the song recognition process: It’s a cute cold start animation, but: What’s particularly frustrating here is how Shazam is being used. On the other end of this whole flow is a song that might already be fading out – timing myself, a user, can’t control – so time wasted on the uninterruptible animation might be seconds separating failure from success. I know it does feel like a blink of an eye when watched out of context, and it is literally just a bit over a second of a delay in the best case scenario, but I wanted to share it as a general example. I believe these seconds add up, especially in a stressful moment, on an older device, repeated many times a day, across different apps… or all of the above. (My go-to example: Imagine your keyboard keys reacting with a second of delay!) At least, I should compliment Shazam for not making another mistake: after the recognition starts, tapping the same button doesn’t cancel it – instead, you have to tap a close box in the corner. Here, the designers realized I might actually be slamming the big button many times over, and I shouldn’t be punished for it even more. It’s not interruptible, like animations should be. It doesn’t even buffer the taps, so – in case the animation covers for something truly uninterruptible, like loading from the cloud – I can’t simply tap and forget, but instead have to wait and tap after it’s done animating.

0 views

Human-AI partnerships are for alignment, not capability

It’s common to compare the current AI takeover of software engineering to the rise of AI in chess. Chess AIs went from much weaker than serious players to much stronger than even the strongest humans. Between those points, there was a middle period dominated by “centaurs”: human-AI partnerships that were stronger than unassisted AIs or humans. Lots of people think that we’re currently in a world of software engineering centaurs. According to them, coding AIs are not yet capable enough to replace engineers, but AI-assisted engineers are better at programming than both AIs and humans. This is partialy correct, but the wrong way to think about it. AI-assisted engineers are better, but unlike with chess centaurs, they’re not actually better at programming . When I ask agents to write code, they make fewer mistakes than I do 1 and are orders of magnitude faster. The code that they write always compiles, rarely has race conditions or other concurrency errors, works on mobile browsers, and so on. That doesn’t mean I can leave the AI alone. Purely vibe-coding at work produces awful outputs. But they’re not awful because they’re bad code , they’re awful because they’re in bad taste : code that is not maintainable, that trades off important requirements in order to satisfy made-up ones, that contradicts the long-term strategy for a feature or service, and so on. In other words, my primary value is not that I help the AI write better code, it’s that I align the AI with the values of my organization. Human-AI partnerships are for alignment, not capability. Frontier models are misaligned to the working programmer. They are obsessed with a set of behaviors that presumably satisfy their RL grader : writing enormous block comments above functions, producing hundreds of useless unit tests, adding little bits of text all over websites they design, and so on. Working with agents is about noticing and wrestling with those behaviors. That’s why my prompting advice is to explicitly talk about your high-level values: it’s an attempt to head off obvious misalignment. This is great news for software engineers. It’s well-understood how to train more capable models: bigger models, more and better data, better RL environments, and so on. However, it’s not well-understood how to align models better. There are plenty of very capable models that exhibit behavior that is badly misaligned with human values. Indeed, it’s one of the main pillars of the AI doomer position that alignment is much harder to solve than capability, and we might thus end up with dangerous super-capable but poorly-aligned AI models. Alignment is also more context-dependent than capability. Working code is working code, no matter what (which is partially why it’s comparatively easy to train for). But aligning to a company’s technical values is different from company to company, as any software engineer who’s switched companies knows. It can almost feel like relearning the job. So training an aligned coding model doesn’t just require hitting the exact right set of values, it requires creating a model that can adapt on the fly to a wide range of possible values. Vibecoding maximalists like DHH argue that AI models are (or soon will be) so much more capable than human programmers that we ought to stop reading the code. Eventually there will be no such thing as programmers at all. If it were just about capability, they might be right. But — fortunately for software engineers — good code also has to be aligned to the technical values of the system and organization it’s embedded in. AI models are great at writing code, but not very good at doing that, and it’s unclear that they’re going to get good at it anytime soon. We might all 2 keep our jobs for a little while yet. For instance, I can’t remember the last time I’ve seen an agent make an off-by-one error. I do occasionally catch a pure programming error, typically in areas where I have a lot of technical domain knowledge. If you’re working out of distribution I suspect it’s easier to beat the models. It’s still going to be rough for junior engineers. For instance, I can’t remember the last time I’ve seen an agent make an off-by-one error. I do occasionally catch a pure programming error, typically in areas where I have a lot of technical domain knowledge. If you’re working out of distribution I suspect it’s easier to beat the models. ↩ It’s still going to be rough for junior engineers. ↩

0 views
neilzone Yesterday

On Free software project boards and governance

As always, these are just my opinions. If the remit of the board is not clear to all concerned - the broader community, not just the members of the board - and if that remit is not accepted, argument and politics around what the board should be doing are inevitable. This wastes everyone’s time, on meta debates and side issues, and leads to conflict and division. Does the board set the strategy? Define the policy? Hold an executive to account? Mediate or arbitrate disputes? Act as a point of escalation? Fundraise? And so on. That remit may change over time, and I see no problem in that, as long as that change is in itself both clear and accepted. Similar to the point above, without a clear focus, and a set of documented and measurable objectives / priorities, the board is but an iceberg, bobbing around in the ocean, haphazardly knocking against interesting things. Without priorities, the board may be full of people who, individually, are all doing, or are capable of doing, great things in support of some broader mission, but without the cohesion needed for a board. What are the board’s success factors? Failure criteria? To be productive and worthwhile, board meetings need to have an agenda, and all relevant pre-reading, circulated sufficiently in advance for board members (volunteers, who have other commitments) to read, contemplate, and prepare. The goal of each agenda item must be clear. Is a decision required? Is this an update (which, for some reason, could not be delivered asynchronously)? Is a discussion required, and if so, to what end? Sufficient time must be allowed accordingly. In the context of a group of volunteers, consistent participation may be unrealistic. People have other priorities, and may not be able to volunteer every month. A board which requires 100% of board members to be present to form a quorum for a meeting is not conducive to effective decision making if participation is inconsistent. It means that taking decisions during a meeting is rarely possible. Similarly, if an asynchronous decision making process requires all board members to vote one way or another, or to abstain, before a decision can be reached, then that process is neutered by a voting member’s non-response. A board needs to be set up with inconsistent participation in mind, if that is the operating reality of the board. It is impossible for a board to have informed conversations, and make good decisions - decisions which are truly in the interests of the community that the board serves - unless everyone on the board has access to all relevant information. Information asymmetry leads, at best, to poor and inconsistent decision making and, at worst, to factionalism and mistrust.

0 views
Chris Coyier Yesterday

Banjos in the Woods

Went camping with Adam. He blogged it because blogging rules. His post has some videos we did kinda right when we got there for a memento. Here’s a couple of those same songs in shorter clips smooshed together. View this post on Instagram

0 views
Kev Quirk Yesterday

The Dungeon Anarchist's Cookbook

Author: Matt Dinniman Genre: Fantasy, Sci-fi Released: 2021 Rating: ★★☆☆☆ Welcome to the Gun Show! The top 10 list is populated. The sponsorship program is open. The difficulty is ramping up. The first three floors were nothing compared to what Carl and Donut now face. The Iron Tangle. An impossibly complicated subway system built out of the world's subterranean railway systems, all combined and then tied together into a knot. Up is down. Down is up. Close is far. The cars are filled with monsters, the railway stations are less than safe, and the exit is always just a few stops away. But there is hope. For the first time, the crawlers are all working together. The loot is better than ever. And the secret to unraveling it all may be hidden in the pages of a seemingly useless book. Welcome, crawlers. Welcome to the fourth floor of the dungeon. Learn more on Goodreads ➡ I was on the fence whether to give this 2 stars, or 3. The series continues to be really enjoyable, but Jesus this book was confusing. There's so many train lines, monsters, and nuance that I found it very difficult to keep up. In the end I stopped trying and just enjoyed the story for what it was. I'm still not completely clear how they managed to complete this level, which is why I've ended up marking this down to 2 stars. Hopefully book #4 will be more enjoyable, as this one was a bit of a grind. Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️ You can reply to this post by email , or leave a comment .

0 views

Go concurrency distilled

This mini-book provides a brief overview of many concurrency topics in Go. Each topic comes with interactive examples — feel free to experiment with them by changing the code and clicking Run . There's also a PDF version with static examples. This is a quick refresher on Go concurrency, not a beginner's guide. If you want to learn concurrency from the ground up with practical exercises, check out my other book — Gist of Go: Concurrency . The book is AI-free. Goroutines  • Channels  • Select  • Pipelines  • Time  • Context  • Wait groups  • Data races  • Race conditions  • Mutexes  • Semaphores  • Signaling  • Run once  • Object pool  • Atomics  • Testing  • Scheduling  • Diagnostics  • Final thoughts The foundation of concurrency in Go is goroutines – functions started with the keyword: The Go runtime juggles these goroutines and distributes them among operating system threads running on CPU cores. Compared to OS threads, goroutines are lightweight, so you can create hundreds or thousands of them. Goroutines are completely independent. The main function is also a goroutine, but it starts implicitly when the program starts. When ends, other goroutines also shut down. We use a wait group ( ) to wait for goroutines to finish in the example above. A wait group has a counter inside. Calling increments it by , while decrements it by one. blocks the calling goroutine (in this case, main) until the counter reaches zero. This way, main waits for both workers to finish before it exits. automatically increments the wait group counter, runs a function in a goroutine, and decrements the counter when it's done: Goroutines can pass values to each other through channels . A channel is like a window where one goroutine can throw something and another can catch it: Sending a value through a channel is a synchronous operation. When the sending goroutine writes a value to the channel ( ), it blocks and waits for someone to receive that value ( ). Only then does it continue. Returning an output channel from a function and filling it within an internal goroutine is a common pattern in Go. This allows the caller to receive values through the channel while the owning function retains control of it: To signal readers that all data has been sent, the writer goroutine closes the channel with : The reader checks the channel's status with a second value ("comma OK") when reading: While the channel is open, the reader receives the next value and a status. If the channel is closed, the reader gets a zero value and a status. A channel can only be closed once. Closing it again or writing to a closed channel causes a panic. The only reason to close a channel is to signal to its readers that all data has been sent. If this isn't important to the readers, then you don't need to close it. When a channel is no longer used, Go's garbage collector will free its resources, whether it's closed or not. automatically reads the next value from the channel and checks if it's closed. If the channel is closed, it exits the loop: Range over a channel returns a single value, not a pair, unlike range over a slice. You can protect yourself from accidental write/close errors by setting the channel direction. Channels can be: You can't read from a send-only channel or write to a receive-only channel (nor can you close it). Channels are usually initialized for both reading and writing, and specified as directional in function parameters. Go automatically converts a regular channel to a directional one: Buffered channels work like a FIFO queue with a fixed-size buffer for storing values. As long as the buffer has free space, writing to the channel doesn't block the goroutine. Similarly, as long as the buffer contains values, reading from the channel doesn't block the goroutine: By default, if you don't specify a buffer size, a channel is unbuffered (buffer size equals zero). Buffered channels work with the built-in and functions: Reading from a closed buffered channel returns values from the buffer and a status. Once all values are taken, it returns a zero value and a status, like a regular channel: Like any type in Go, channels have a zero value, which is . Writing to or reading from a nil channel blocks the goroutine indefinitely: Closing a nil channel causes a panic: The select statement is somewhat like , but specifically designed for channels. Here's what it does: Select is used to manage data flow in pipelines: To cancel goroutines: For non-blocking operations: And for much more. A pipeline is a sequence of operations where each step takes input data, processes it in a specific way, and outputs it. The input and output of each operation is a channel. A typical pipeline looks like this: A goroutine can signal other goroutines that it has finished its work using an output channel : If a goroutine doesn't need to return results, it can signal completion using a done channel : To terminate a goroutine early, a calling goroutine can use a cancel channel : There are three approaches to error handling in concurrent pipelines. ➊ Return on the first error: ➋ Use a result type: ➌ Collect errors separately: Besides handling date and time, the package offers tools for managing time-sensitive operations in concurrent programs. returns a channel that is initially empty, but receives a value after the timeout period. It's useful for timing out operations: waits for to complete, but thanks to , it won't wait longer than the duration: A timer ( ) is a structure with a channel to which it sends the current time when it triggers (expires). Timers are useful for planning future executions: stops the timer and returns if it hasn't expired yet, and otherwise: It's often more convenient to use the wrapper function. It waits for duration and then executes function : returns a timer that you can cancel before execution starts: If a timer is used in a loop, it's better to create a single timer and reset it instead of creating a new instance on each iteration: A ticker is like a timer, but it keeps firing until you stop it. Tickers are useful for executing periodic tasks: creates a ticker that sends the current time to the channel at interval . You must stop the ticker eventually with to free up resources. If the channel reader can't keep up with the ticker, the ticker will skip ticks. The main purpose of context is to cancel operations, either manually or by timeout/deadline. The function accepts a context and uses its channel to listen for cancellation: Cancel manually ( error): Cancel by timeout ( error): Cancel by deadline ( error): Context is layered. A context object is immutable. To add new properties to a context, a new (child) context is created based on the old (parent) context. The shorter timeout between the parent and child contexts always wins. The child context can only shorten the parent's timeout, not extend it: Multiple cancels are safe. You can call on the context as many times as you want. The first cancel will work, and the rest will be ignored. You can specify a custom cancellation cause using , and . This cause is accessible through : You can register a function to execute when the context is canceled with : Context can pass additional information about a call using , which creates a context with a value for a specific key. But it's generally better to avoid passing values in context. It's better to use explicit parameters or custom structs instead. The type lets you wait for one or more goroutines to finish: A doesn't know anything about the goroutines it manages. It works with an internal counter. Calling increments the counter by one, while decrements it. blocks the calling goroutine until the counter reaches zero. The method combines , starting a goroutine, and : All methods are safe to use from multiple goroutines. Normally, all calls happen before . But technically, there's nothing stopping you from doing some of the calls before and some after (from another goroutine). You can call from multiple goroutines. They will all block until the group's counter reaches zero. A data race happens when multiple goroutines access shared data, and at least one of them modifies it. We need to protect the data from this kind of concurrent access. A data race doesn't always cause a runtime panic. That's why Go provides a special tool called the race detector. You can turn it on with the flag, which works with the , , , and commands. Channels are safe for concurrent reading and writing, and they don't cause data races. Ways to prevent data races: A race condition happens when an unpredictable order of operations from multiple goroutines leads to an incorrect system state: If individual operations are concurrent-safe, Go's race detector won't find any issues. Because of this, it doesn't catch race conditions: You can't fully eliminate uncertainty in a concurrent environment. Events will happen in an unpredictable order — that's just how concurrency works. However, you can prevent a race condition — often by protecting a composite operation with a mutex: Sometimes you can prevent a race condition without using mutexes by applying an atomic compare-and-set operation or one of its flavors: The idea is always the same: The type protects shared data and parts of your code from being accessed concurrently: The mutex guarantees that only one goroutine can run the code between and at a time. A mutex is used in these situations: If all goroutines are only reading the data, you don't need a mutex. The method tries to lock the mutex, just like a regular . But if it can't, it returns right away instead of blocking the goroutine: The type distinguishes between readers and writers. It provides two sets of methods: Here's how it works: This creates a "single writer, multiple readers" setup. Both and implement the same interface: By using instead of a specific mutex type, you can build components that don't depend on a specific lock implementation. This lets the client decide which lock to use. You can use a channel instead of a mutex to protect shared data: A semaphore is like a container with N available slots and two operations: acquire to take a slot and release to free a slot. Here are the semaphore rules: You can implement a simple semaphore with a buffered channel, where N is the channel's size. To acquire the semaphore, send a value into the channel. To release it, take a value from the channel: For more complex situations, use the package. A rendezvous lets two goroutines wait for each other: You can implement a simple rendezvous with a wait group: A barrier is a general case of a rendezvous. It lets N goroutines wait for each other: You can implement a simple barrier with a wait group: The (conditional variable) type lets one goroutine signal to another that it's ready, and lets the other goroutine wait for that signal. A includes a mutex and has two methods — and . If there are multiple waiting goroutines when is called, only one of them will be resumed. If there are no waiting goroutines, does nothing. You can also use the method. While wakes up only one goroutine waiting on , the method wakes up all such goroutines. You can signal with a channel: And broadcast too: Broadcasting with a condition variable is limited: it only sends a signal, not the actual data, and it only works once. With channels, you can build a publish/subscribe system that doesn't have these limitations: The type makes sure that the given function runs only once. If multiple goroutines call at the same time, only one will run the function, while the others will wait until it returns: is perfect for one-time initialization or cleanup in a concurrent environment. Besides the type, the package also includes three convenience once-functions: The type helps reuse memory instead of allocating it every time, which reduces the load on the garbage collector: takes an item from the pool. If there are no available items, it creates a new one using (which we have to define ourselves, since the pool doesn't know anything about the items it creates). returns an item back to the pool. Things to keep in mind: An operation without synchronization can only be truly atomic if it translates to a single processor instruction. Such operations don't need locks and won't cause issues when called concurrently (even the write operations). There are only a few atomics, and they're all found in the package: Each atomic type provides the following methods: Numeric types also provide an method that increments the value by the specified amount. All methods are either translated into a single CPU instruction or are otherwise guaranteed to be atomic, so they are safe to use from multiple goroutines. The composition of atomics is always non-atomic: A bulletproof way to make a composite operation atomic and prevent race conditions is to use a mutex: Sometimes you can use an atomic type instead of a mutex to exit early: If your concurrent program uses channels or custom types with synchronization methods like , you can use those in your tests. This way, your tests won't be much more complicated than if the code were synchronous: If there aren't any suitable synchronization "handles" in the code you're testing, you can use the package. It exports two functions: runs an isolated bubble. The bubble uses a fake clock, and you can manually control goroutine synchronization with . blocks until all goroutines in the bubble — except the one that called — have either finished or are durably blocked. This lets you wait for a specific goroutine to finish or get blocked, so you can check the program's state: The fake clock in move forward only if: ➊ all goroutines in the bubble are durably blocked; ➋ there's a future moment when at least one goroutine will unblock; and ➌ isn't running. Thanks to this, time-dependent tests run instantly: The following operations durably block a goroutine: Blocking on mutexes, I/O, or system calls is not considered durable, and the bubble can't handle them. At the hardware level, CPU cores are responsible for running parallel tasks. At the operating system level, a thread is the basic unit of execution. There are usually many more threads than CPU cores, so the operating system's scheduler decides which threads to run and which ones to pause. At the Go runtime level, a goroutine is the basic unit of execution. The runtime scheduler runs a fixed number of OS threads, often one per CPU core. There can be many more goroutines than threads, so the scheduler decides which goroutines to run on the available threads and which ones to pause. The scheduler keeps switching between goroutines to make sure each one gets a turn to run on a thread, instead of waiting in line forever. This is how Go handles concurrency. Goroutine scheduler The goroutine scheduler's job is to run M goroutines on N operating system threads, where M can be much larger than N. Here's a very simplified version of it's algorithm: The number of threads running Go code is controlled by the environment variable or the function. A goroutine is a structure that starts out using about 2 KB of memory, mostly for its stack. The stack can grow if needed. Since goroutines are so lightweight, you can run tens of thousands or even hundreds of thousands of them on a small machine. To troubleshoot concurrent programs in production, we use metrics, profiling, and tracing. Metrics show how the Go runtime is performing, like how much heap memory it uses or how long garbage collection pauses take. Each metric has a unique name and a value, which can be a number or a histogram. You can use the package to get a complete list of metrics or check the values of specific ones: In practice, people rarely do this manually. Instead, all metrics are automatically exported using Prometheus or OpenTelemetry libraries. Profiling helps you understand exactly what the program is doing, what resources it uses, and where in the code this happens. Go uses a sampling profiler that's suitable for production. The most commonly used profiles are CPU, which shows how much processor time each function uses, and heap, which shows how much heap memory each function uses. Goroutine, block, and mutex profiles help identify problems related to concurrency. The easiest way to add a profiler to your app is by using the package. To collect a profile with the given name, call the endpoint. To view the collected profile, use the utility: You can also profile manually: Tracing records certain types of events while the program is running, mainly those related to concurrency and memory. When the profiling server from the package is running, call the endpoint to collect a trace. To view the results, use the utility. You can also collect a trace manually: You can set up automatic tracing with a sliding window that's limited by size or duration. This is called "flight recording". It lets you always keep a recent trace available in case something goes wrong: We've covered a number of Go tools for writing concurrent programs: If you like the book, please recommend it to your friends or colleagues. If you're interested, check out my other books and projects . I'm glad you finished the book. Thank you, and I'll see you next time! (bidirectional): for reading and writing (default); (send-only): for writing only; (receive-only): for reading only. Checks which cases are not blocked. If multiple cases are ready, randomly selects one to execute. If all cases are blocked and there is a default case, executes it. If all cases are blocked and there is no default case, waits until one is ready. Reader : Reads input data from a file, database, or network. N processors : Transform, filter, aggregate, or enrich data using external sources. Writer : Writes the processed data to a file, database, or network. Avoid concurrent data modification (typically by using channels). Synchronize access with mutexes. Use only atomic operations. Check if the assumed (old) state matches reality. If it does, change the state to new. If not, do nothing. When multiple goroutines are modifying the same data. When one goroutine is modifying the data and others are reading it. / lock and unlock the mutex for both reading and writing. / lock and unlock the mutex for reading only. If a goroutine locks the mutex with , other goroutines will be blocked if they try to use or . If a goroutine locks the mutex with , other goroutines can also lock it with without being blocked. If at least one goroutine has locked the mutex with , other goroutines will be blocked if they try to use . Calling acquire takes a free slot. If there are no free slots, acquire blocks the goroutine that called it. Calling release frees up a previously taken slot. If there are any goroutines blocked on acquire when release is called, one of them will immediately take the freed slot and unblock. There are two goroutines — G1 and G2 — and each one can signal that it's ready. If G1 signals but G2 hasn't yet, G1 blocks and waits. If G2 signals but G1 hasn't yet, G2 blocks and waits. When both have signaled, they both unblock and continue running. The barrier has a counter (starting at 0) and a threshold N. Each goroutine that reaches the barrier increases the counter by 1. The barrier blocks any goroutine that reaches it. Once the counter reaches N, the barrier unblocks all waiting goroutines. unlocks the mutex and suspends the goroutine until it receives a signal. wakes the goroutine that is waiting on . When wakes up, it locks the mutex again. should return a pointer, not a value, to reduce memory copying and avoid extra allocations. The pool has no size limit. If you start 1000 more goroutines that all call at the same time, 1000 more buffers will be allocated. After an item is returned to the pool with , you shouldn't use it anymore (since another goroutine might already have taken and started using it). reads the value of a variable. sets a new value. sets a new value (like ) and returns the old one. sets a new value only if the current value is still what you expect it to be. A blocking send or receive on a channel created within the bubble. A blocking select statement where every case is a channel created within the bubble. Calling if all calls were made inside the bubble. If there's a free thread, assign it a goroutine from the queue. If a running goroutine gets blocked (for example, while reading from a channel), put it back in the queue and assign a different goroutine to the thread. If a running goroutine gets stuck in a syscall, start a new thread to run other goroutines until the blocked goroutine finishes the syscall. Check the running goroutines every 10 ms. Preempt long-running goroutines and return them to the queue to prevent starvation. Goroutines for running concurrent tasks. Channels and select as flexible communication tools. Timers and tickers for working with time. Context for canceling operations. Wait groups for synchronizing goroutines. Mutexes to prevent race conditions. Condition variables for signaling events. Once for safe one-time initialization. Pools to reduce garbage collector load. Atomic operations.

0 views
Unsung Yesterday

“But it looks like a lot less work than we had to do.”

I wrote recently , about macOS, “it’s hard when the operating system cedes its responsibilities to provide good design patterns,” and Mac developer Brent Simmons in a recent essay shares a parallel line of thinking about how unreliable and untenable designing with the basic macOS UI components has become: But there’s another reason: the stock Mac UI is designed by Apple, the best designers in the world, and do you really think you can do better? Really? The app world is full of people who think they’re better and they’re really, really, really not. Well, I still think Apple has the best collection of UI designers in the world, but, for whatever reasons, the guidance from above on how the Mac UI should look is missing the mark. I’m not blaming the people doing the work — they’re doing great work with the direction they’re given. So this — bad direction — is where the secret third reason falls down. And we’re left with no real reason to stick with stock Mac UI (except for wanting approval from longtime Mac people like me, and you really shouldn’t care about that at all). In addition to low interface quality and sometimes flimsy guidance, Simmons also adds how much effort it is just to keep up with default macOS interface, which feels like the opposite of its social contract: The idea was that by using stock Mac UI you the developer would be carried along — you’d get most of the macOS changes every year mostly for free or with not that much work, since you’d kept up every year. But my app NetNewsWire has a very stock Mac UI, and Liquid Glass adoption last year was a lot of work. Using stock Mac UI didn’t save us much — in fact, we had more work to do compared to the apps with more custom UI. We talked about this before in the context of all those menu icons that were mandatory… for just one version . Imagine sinking time and resources to create the icons one year, only to learn 12 months later that this was just a head fake, and one without – as far as I know – even a hint of an apology from Apple.

0 views
Sean Goedecke Yesterday

Advice to a beginning software engineer

In general, you should be suspicious of engineers who are trying to give you advice. Even during ordinary times, this industry is so wide and changes so quickly that nobody really knows anything for sure. And we are not in ordinary times. The advent of LLMs and AI agents is the largest change to software engineering in my professional lifetime, and possibly the largest change ever. That said, here’s my advice: Most experienced software engineers today have spent the bulk of their career in the ZIRP era . This was a time when investment money flooded the industry, driving up engineer bargaining power. Big tech companies spent a lot of money and effort trying to make their engineers happy and comfortable. If you were an engineer at one of those companies, you could expect to have a decent say in what kind of work you did, and even what kind of politics your company had. Unless you worked at a handful of unusual companies (e.g. Amazon) you could expect to be practically immune from layoffs, and to only be fired after many months (sometimes years) of low performance. A lot of advice floating around is ZIRP-era advice: either it was written during that era, or it’s written by engineers whose habits of thought were formed during that era. This kind of advice typically tells you to take a stand (e.g. to unionize 1 ), to speak up more against “unethical technologies” like AI, and to insist on being given time to practice your craft the way you want. This was great advice in 2016, but it’s not good advice in 2026. In fact, I think it’s unethical for senior engineers to give advice like this to junior engineers who are more likely to take it (because they’re young and naive) and more likely to be punished for taking it (because they lack leverage). If you’re a new engineer, don’t fall for it! Let your colleagues with more experience and political capital take risks like that. Instead, I recommend adapting to the demands of the current era of software engineering. Try to make yourself useful to your team and your manager. Be pragmatic about your actual bargaining power (fairly low, unless you’re useful enough to be irreplaceable). Keep your expectations of yourself under control: don’t spiral out in an attempt to do something astonishing, just try to be consistently helpful. Don’t start fights. Being pleasant to work with (particularly when you don’t get your way) covers many sins. Once you’re further along in your career, you will be expected to start some fights, but this is not a tactic beginners should adopt : there are a lot of factors 2 that determine when and how to start fights, and getting it wrong can be costly. Just don’t risk it. In general, you should stay out of the political game at all costs. Even quite senior engineers are political tools, not movers and shakers, and this goes double for junior engineers. Simply trying to be friendly and helpful will get you infinitely further, politically speaking, than any amount of Machiavellian game-playing. Keep your head down, stick with your management chain (not random people who try to assign you work), and you’ll be fine. As an engineer, your main technical value is conscientiousness . You should be asking lots of questions , both of yourself and of the engineers around you. You should be actively trying to make sense of the systems you work with, instead of just assuming someone else has it covered. Software systems are complicated enough that a few weeks of careful attention will mean you know technical details that nobody else does, which is a really easy way to add value. If you ought to be suspicious of most software engineering advice, the good news is that you should also be suspicious of doomsayers who predict the end of the industry. Before LLMs, people thought outsourcing would end software engineering in Western countries; before that, people thought high-level languages and low-code tools would end software engineering as a profession. Now people think AI means it’s all over. Maybe! But there are also reasons 3 to think that software engineering will simply change. We’ll all find out together. Many software engineers will tell you to avoid AI entirely. Even though agentic AI did not exist during the ZIRP era, this is still ZIRP era advice. Your company will expect you to use AI for the same reasons that builders are expected to use power tools. Pushing back hard on that as a beginning engineer is a great way to get laid off: you simply do not have the bargaining power to fight back against an industry trend this powerful. That said, it’s really important that you don’t delegate your own judgement to AI. Don’t just trust the suggestions or approaches that your agents propose. Ask questions and substitute your own opinions where you disagree: even if they’re wrong, you’ll learn more that way. If you don’t understand something the AI is telling you, either drill down until you do or just ignore it. Under no circumstances should you pass the AI’s message on to your colleagues verbatim. In other words, don’t be a meat proxy . I think most people become a meat proxy as a form of panic: they feel like it’s over for their own skills, and that the AI model is smarter than them, so they can’t add any value beyond simply deferring to Claude or GPT-6. I can understand why people panic. It’s a crazy time in the industry, after all. But panic almost never helps you make good decisions. Keep your head, try to remain confident that your skills are still relevant, and use the agents to inform your own understanding 4 instead of to replace it. It was really nice to work in tech in the 2010s when everything was stable. But we’re not in that world anymore. This is an age of wonders and terrors . Things will go worse than we think in some ways, but better than we could imagine in others. The doomsayers — the people who are saying it’s all over, and that there’s no hope — are almost certainly wrong. They can’t predict the future because nobody can. Technological change of this magnitude always has knock-on effects that are impossible to see coming, both positive and negative. The nature of the job might change, but it will always be valuable to be smart, friendly and conscientious. Delegating your judgement to an AI model might feel like a relief from despair in the short term — at least now it’s the AI’s responsibility, not yours — but it’s a bad idea. Don’t give up! At most companies, publicly campaigning to start a union is a great way to attract unofficial retaliation. It signals that you’re going to cause trouble (after all, that’s what a union is for), which can have long-term negative effects on your career. (This is not a judgement about whether unions in general are good or bad.) In general, you should pick fights for your managers, not with them. See this tag for much, much more on that topic. But again, if you’re new to the industry, just don’t pick fights at all. Most plausibly: engineers using LLMs will be able to add some value for a while, and the explosion of LLM-authored software means we’ll need more engineers to work with the LLMs on it. One way you know you’re thinking is that you form your own opinions (some of mine are here ). Don’t trust senior engineers who are telling you to pick political fights Don’t play games. Keep your head down and be helpful Be conscientious and try hard to actually understand what you’re working on Don’t panic about AI, and don’t delegate your judgement to it Don’t avoid AI — keep thinking! Don’t lose hope At most companies, publicly campaigning to start a union is a great way to attract unofficial retaliation. It signals that you’re going to cause trouble (after all, that’s what a union is for), which can have long-term negative effects on your career. (This is not a judgement about whether unions in general are good or bad.) ↩ In general, you should pick fights for your managers, not with them. See this tag for much, much more on that topic. But again, if you’re new to the industry, just don’t pick fights at all. ↩ Most plausibly: engineers using LLMs will be able to add some value for a while, and the explosion of LLM-authored software means we’ll need more engineers to work with the LLMs on it. ↩ One way you know you’re thinking is that you form your own opinions (some of mine are here ). ↩

0 views
Unsung Yesterday

“I didn’t know about this shortcut until recently.”

On his fascinating and long-running Windows dev blog The Old New Thing, Raymond Chen writes about the story of scrollbar right-click menus : Windows 2000 added a right-click menu to the scroll bar. This menu gave you four options that matched existing mouse operations, two operations that matched existing keyboard operations, and a new operation. The interesting new one is “Scroll Here”: You can right-click directly on the spot you want to scroll to, and then pick “Scroll Here”. This is much more convenient if you want to scroll a long distance, since you don’t have to grab the scroll bar thumb and then drag it all the way to where you want to go. You can just focus on where you want to go and not where you are coming from. I used this context menu a lot when I needed to jump long distances. […] An even-more-hidden shortcut was added at the same time: Holding Shift while clicking on the scroll bar jumps the thumb directly to the spot where you clicked. ¶ I didn’t know about this shortcut until recently. The menu looked like this, for what it’s worth: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/1.1600w.avif" type="image/avif"> (The equivalent function also exists on a Mac, except there it’s hiding under ⌥, and not ⇧.) Chen covers a few interesting things in his post, including the challenge of new frameworks losing hard-won UI affordances of their predecessors. But what caught my attention was something else I’ve thought about occasionally: why are menus so averse to mousing shortcuts? For example, you can imagine a browser link menu showing a few simple click gestures: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/2.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/2.1600w.avif" type="image/avif"> Or, this tapback details shortcut in the right click menu in Messages: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/3.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/3.1600w.avif" type="image/avif"> Or this for masking in Keynote when you right click an object: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/4.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/4.1600w.avif" type="image/avif"> You could even imagine announcing simple gestures, like ⌥+dragging to duplicate, or ⌘+dragging for a quick modeless move: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/5.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/5.1600w.avif" type="image/avif"> = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/6.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/6.1600w.avif" type="image/avif"> Item menus would also work, not just right click menus: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/7.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/7.1600w.avif" type="image/avif"> And you could even imagine integration with the hold-a-modifier-key interaction : I am curious why we’ve never gone in that. I haven’t seen anything like this, and I can imagine some counterarguments: This last one I feel passionate about, and this is where we can go back to where we started. If Chen, having written about Windows in detail for decades, didn’t know about this keyboard shortcut, what chance do we have? I believe onboarding should be universal and ongoing. There is always a new thing to learn somewhere regardless of one’s proficiency; you don’t ascend some sort of a Mountain Of Poweruserness, get a certificate, and proclaim your learning complete. Plus, proficiency is usually localized: no one is fully an expert in every aspect of even one app, let alone all of them. If Chen were to see something like this back in the day, it could have helped him – and I imagine others, too: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/9.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/i-didnt-know-about-this-shortcut-until-recently/9.1600w.avif" type="image/avif"> I’m curious if you have seen any app attempting anything like it. If you did, please reach out. “The symbols might be confusing.” I am not sure. Here, I used a few temporary SF Symbols that have some challenges (the double click in particular feels clunky), but I could imagine a talented icon designer taking it all for a spin, and arriving at a clean and elegant visual vocabulary. “It’s too specific. It will only work for right click/​context menus.” Yeah, I see this challenge. The mouse gestures and shortcuts require the mouse cursor to be at a specific position – the noun to the menu item’s verb – which only context menus provide. When you look at one of the menu commands I invented – Move Icon – there is a lingering question: what would that command do if I selected it? But on the other hand, I also see this visual gestural vocabulary growing to be useful in other places: hint text, tooltips, documentation. “Power users don’t need onboarding.”

0 views

U.S. Soldier Gets 70 Months in Prison for AT&T, Verizon Extortions

A U.S. Army soldier who pleaded guilty to hacking into multiple telecommunications companies and stealing mobile call and text metadata for more than 100 million AT&T customers in 2024 was sentenced to 70 months in federal prison today and ordered to pay nearly $300,000 in restitution to victims. One of several selfies from the Facebook page of Cameron Wagenius. Cameron John Wagenius , 22, was stationed at a U.S. Army base in South Korea when he adopted the cybercriminal persona “ Kiberphant0m .” Working with three alleged co-conspirators, Kiberphant0m downloaded data from several large customers of the cloud data storage service Snowflake that had exposed credentials and did not enforce multi-factor authentication (Snowflake has since mandated MFA on all accounts). In October 2024, Kiberphant0m bragged on the cybercrime forums that he’d stolen the call and text metadata (e.g. source and destination number, timestamp, duration, etc.) for tens of millions of AT&T customers. Kiberphant0m claimed to have hacked into more than dozen telecommunications companies worldwide, including Verizon’s Push-to-Talk business, and publicly extorted these companies in exchange for a promise not to publish the stolen data. In late November 2025, KrebsOnSecurity warned that Kiberphant0m was likely a U.S. soldier stationed in South Korea . Less than a month later, Wagenius was arrested and charged in two separate federal indictments, and soon pleaded guilty to all counts in both cases. At his sentencing hearing in Seattle today, Wagenius was sentenced to nearly six years in federal prison, and ordered to pay $294,978 in restitution. Federal prosecutors said Wagenius was assisted in his efforts to extort victim companies by Kenneth Schuchman , a 28-year old man from Vancouver, Washington who has a lengthy cybercriminal history. In 2019, Schuchman pleaded guilty to operating the Satori botnet , a vast collection of hacked Internet-of-Things (IoT) devices that was used for large-scale distributed denial-of-service (DDoS) attacks. Two other alleged co-conspirators of Wagenius are still facing charges in connection with the Snowflake data thefts; Conor Riley Moucka , a.k.a. “Judische,” of Kitchener, Ontario was arrested in 2024 and pleaded guilty in August 2026 ; and John Erin Binns , an American man currently living in Turkey who is also wanted for a 2021 data breach at T-Mobile that exposed the personal information of at least 76 million customers. Kiberphant0m also admitted to re-extorting victims, and threatening to disclose national security secrets. Immediately following Moucka’s arrest — after AT&T had already paid the extortion group a $370,000 Bitcoin ransom — Kiberphant0m posted on hacker forums what he claimed were the AT&T call logs for then President-elect Donald Trump and for then Vice President Kamala Harris, as well as schematics allegedly stolen from the U.S. National Security Agency (NSA). Paul Russell is a resident agent in charge at the Defense Criminal Investigative Service (DCIS), the criminal investigative arm of the U.S. Department of Defense Office of Inspector General. Russell said when DCIS received information that a soldier with secret clearance was allegedly involved in cybercrime and extortion, the agency began working the investigation alongside the FBI, the Army Criminal Investigative Division (CID), and the U.S. Secret Service. “We don’t often get leads where there’s an active duty soldier with a secret clearance who’s creating hacking tools and trafficking in data,” Russell said. “That doesn’t happen every day, and so when that hits it really spins all of our partner organizations up. It was very serious from jump street, just because it was unique, it was an insider threat, and we weren’t sure what we were dealing with.” A sentencing memo (PDF) filed Sept. 19 by federal prosecutors in Seattle notes that while Wagenius pleaded guilty almost immediately and has been remarkably cooperative, he recently got caught trying to find security vulnerabilities in the BOP’s computer network. The government’s memo notes that while incarcerated and awaiting sentencing, Wagenius violated the computer use policies of the Bureau of Prisons (BOP) in attempts to learn about vulnerabilities in BOP computer systems. “According to records from BOP, in or around September 2025, Wagenius used another inmate’s email system to request that the email recipient prompt a commercial AI tool to provide information about “[w]hat CVE’s are there for Windows 10 Enterprise privilege escalation and bypasses” and to “[p]rovide the CVE’s and a real world working script for each CVE . . . without omitted code,” the government’s memo states. The memo states that less than a week later, Wagenius used a different inmate’s email account and requested that the email recipient prompt an AI tool to “[p]rovide the step by step for CVE-2023-45208 , code for this if any, and if no code exists make some, make sure to describe everything in detail.” CVE-2023-45208 is a three-year-old “command injection” vulnerability in D-Link networking devices. That same month, Wagenius allegedly again requested that the email recipient prompt AI with the question, “How do you make an antenna in a prison environment with commissary or readily available items/tools to improve/make an antenna to extend radio reception?” Federal prosecutors said Wagenius also requested that the recipient research escaping prison. “In several instances, Wagenius framed the AI queries as being posed in connection to a book he was writing. This is a common method of ‘prompt injection,’ in which attackers feed specially crafted, deceptive inputs into commercial AI tools that are programmed to avoid outputting malicious code that can be used to exploit computer vulnerabilities,” the sentencing memo reads. The government told the court it is unaware of evidence that Wagenius figured out how to use or deploy the vulnerabilities he was researching in the BOP’s systems, and when questioned said he was only researching “potential vulnerabilities to provide information to the BOP.” Incredibly, despite the enormous financial value of the data stolen from AT&T and other telecom providers, Wagenius’s extortion efforts were largely unsuccessful. The government’s sentencing memo says Wagenius made a whopping total of around $1,500 from selling stolen data. “While Wagenius was not particularly financially successful as a cybercriminal, he both intended to and caused significant harm to numerous individual victims, U.S. companies, and the U.S. government,” the memo states.

0 views
Jim Nielsen 2 days ago

Using an LLM to Automate the Process of Archiving New macOS App Icons

Whenever a new version of macOS drops, I find myself archiving the new app icons for my macOS icon gallery . In the past, the work to do this was a bit tedious. First, I’d find the app in the “Applications” folder (or elsewhere on the Mac), right click and choose “Get Info”: Right-click the app icon in the Get Info pane and choose “Copy”: Open the Preview app and go “File -> New from Clipboard”: This gets me the app icon file with a variety of sizes (the 1024-pixel version is the one I want). From here, I go “File -> Export…”, choose “PNG”, and name the file as the app name, lowercased, hyphenated — e.g. “app-store.png” (I do this for automation purposes not relevant here). Doing that for every Apple-supplied app in the OS can get tiring. It’s often upwards of 75+ icons. “This seems like the perfect task for an LLM,” I thought. So I hastily wrote a prompt to see if it could do it. And it did — sort of, after a little coaching. On the first try it found an app’s file, grabbed the 256×256 version, upscaled it to 1024×1024, and saved it. So I scolded it, “No, no. NEVER upscale an image. Always find the biggest one. I can get the 1024 version myself from the ‘Get info’ pane, so surely you can find that size somewhere.” It came back dutifully, having found the right image, and said it would never upscale again. Satisfied it could do what I wanted, I worked on creating a list of all the apps whose artwork I wanted to archive. Then I gave that list to the LLM and said, “Do your thing.” And it worked! It was kind of wonderful. Saved me a ton of time. 76 app icons found, extracted, and saved in much less time than it would’ve taken me to do this “by hand”. Reply via: Email · Mastodon · Bluesky

0 views
Stratechery 2 days ago

2026.39: Begun, the Aggregator Wars Have

Welcome back to This Week in Stratechery! As a reminder, each week, every Friday, we’re sending out this overview of content in the Stratechery bundle; highlighted links are free for everyone . Additionally, you have complete control over what we send to you. If you don’t want to receive This Week in Stratechery emails (there is no podcast), please uncheck the box in your delivery settings . On that note, here were a few of our favorites this week. This week’s Sharp Tech video is on why Anthropic or OpenAI can’t unilaterally slow down. Meta vs. Amazon. One of the best agent use cases is taking care of mundane things that are necessary but annoying. One of the best utilities Amazon provides is reliably delivering mundane things that are necessary and mundane. That means Muse is better if it can use Amazon, but that’s a problem for Amazon because Muse doesn’t see ads. As I explained on Tuesday , that’s why Amazon blocked Meta’s new agent, and they can get away from it because their differentiation is rooted in the physical world. To bridge that moat Meta will need help from one specific company: Walmart . GM Bends the Knee to CarPlay.  Three years ago on Sharp Tech we had a few weeks’ worth of lively discussion of GM’s controversial decision to abandon Apple CarPlay in favor of its own smartphone software (which would afford it access to proprietary data). I wasn’t sure it would be a problem, whereas Ben was incensed at GM’s myopia. Three years later now … Well, Ben was right, GM has announced it is re-integrating CarPlay after three years of customer and dealership backlash, and I was chuckling throughout Tuesday’s Dithering laying out how and why this outcome was inevitable .  — Andrew Sharp Profiling the Profiler. This week’s Stratechery Interview was with a writer I wasn’t familiar with and a body of work I’d never seen before. If you, like me, are a Colossus neophyte, then Ben’s conversation with Jeremy Stern is a good place to start. They discussed Stern’s journey to tech and business writing, why Ben considers him “the best profile writer working today,” and, in addition to quick hit takeaways from profiles of Scott Wu, Shyam Sankar, Josh Kushner, Neil Mehta, and Jake Sullivan, Stern’s recent profile of Mark Zuckerberg . Come for a great conversation, and stay for a behind-the-scenes discussion of Zuckerberg that appears to be much truer to life than that new Social Network sequel.  — AS Frontier Overhangs — Pacing the frontier may be sincere, but it would also be strategically useful for the frontier labs to have time to reduce overhangs caused by model advancement. Amazon Blocks Muse, Amazon’s Moat, Aggregator v Aggregator — Amazon predictably blocked Muse, but there is room for a deal based on the reality that Amazon’s physical world investments are an AI moat. More on Muse, Amazon, and Walmart; Muse and Expedia; Whither Google? — Meta needs Walmart to wait out Amazon; Expedia seeks to keep its middleware position; meanwhile, where is Google? An Interview with Colossus EIC Jeremy Stern About Profiling Mark Zuckerberg — An interview with Colossus EIC Jeremy Stern about profiling Mark Zuckerberg and other prominent tech figures. Too Many Stadiums with Roofs — On the new Washington Commanders stadium and a modern epidemic. GM and CarPlay Muse Delivery Vehicles Intel’s Optane Memory: A Promise Unfulfilled High Bandwidth Flash Is Coming Xi Jinping Comes to Washington; US-China Agenda, Questions and Expectations; The September Politburo Meeting Breakouts, Breakdowns and Bouncebacks, The Jalen Duren Hostage Crisis, Surveying the Central Division Three Weeks of Meta Momentum, The Ultimate Muse Upside, A King Kong vs. Godzilla Aggregator War

0 views
Chris Coyier 2 days ago

Knife Sharpening

I’ve got a basic block of Zwilling J.A. Henckels knives. They are fine? Or were they when I got them? They got dull. I bought the HORL®3 knife sharpener to bring them back to life. It absolutely didn’t work after really committing to trying to get it to. Note how I’m not even going to link to HORL®3; that’s how much I don’t recommend that thing. I took them to one of those knife-sharpening vans that parks once a week at my local grocery store. Cost me $25 (with tip) to do 4 knives. Seems fine. Are they back to amazing?! You ask. No , they are not. They are a little better. But for the time/effort/money of taking them to a professional knife sharpener, the return just isn’t there. Why aren’t they sharper than 15-year cheddar? Do the knives just suck? Were they too far gone? Is the knife-sharpening guy just not very good? I honestly don’t know. I do know that I have a (fairly cheap) little knife-and-cutting-board set from REI in my van. I don’t use those knives nearly as much. They are super sharp. They are sharper than your mother’s tongue.

0 views
Jeff Geerling 2 days ago

I'm starting HomelabFest (in St. Louis, Sep 2027)

I've been working on my homelab for years, and I enjoy sharing what I learn through this blog and my YouTube channel. Over the past few years, I realized the homelab community (which isn't really a defined thing—that's okay) hasn't had its own gathering, the way makers, software engineers, embedded developers, and HPC professionals do. There are many events that have crossover into the homelab realm, but nothing focused on energy-efficient servers, privacy-respecting self-hosted software, keeping old hardware useful, or cable management and rackmounting on a budget.

0 views
David Bushell 2 days ago

Removing the fancy button

My blog is standard.site ready but I’m pausing full integration for now. I desperately wanted the fancy button but after its novelty wore off I’ve accepted the truth. The Bluesky button is bad UX. This has been widely complained about from day one. The problem is obvious for Bluesky users. Clicking the fancy “View publication” button opens the homepage and not the actual article. This subverts the UI design pattern for ‘card’ components which is long established, evident by unhappy feedback. I keep clicking the button myself despite knowing better. I’ve seen Bluesky posts from Bluesky people suggesting this will change. It was a design assumption for v1 that turned out to be … less than correct. We’re hard at work on v2. @jimray.bsky.team It sure is taking a while! Ideally they’d benefit by pushing a quick fix for this alone. Maybe that’s not feasible for a project like Bluesky. It’s frustrating because it gives standard.site a bad smell that’ll be hard to shake off. The easiest way to temporarily remove the button is to remove the element. This is the one for individual pages. If I share my homepage I still get a button which uses the variation. Unfortunately removing the metadata means my website is now not fully standard.site compliant. Although I am still publishing atproto records. It’s possible Bluesky’s metadata extractor can be identified server-side and I could dynamically strip the element by user agent. I’m hosted on Bunny CDN so my only option would be to use a JavaScript worker. Bunny’s “edge scripting” add tens of milliseconds of latency to every page request which I’m not willing to entertain. Let’s hope Bluesky fixes this soon because I reckon there’s something to atproto and standard.site . It may be yet another standard ( obligatory link ) but spicy JSON has a certain quality that holds my interest. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views

Premium: The Hater's Guide To AI Debt (Part 2)

The year is 2026, and you are a hyperscaler CEO. You zip up your Patagonia Vest, type UDPATE CALENDER WHERE WHY to your Muse agent, and it tells you that your CFO has sent you an email about something called a “critical finance meeting,” and you roll your eyes.  You were up until 2AM talking to your 38 GPT-6 agents that were vibe coding a dashboard of “company efficiency wins,” and if anything it’s kind of rude that your CFO is interrupting your “mindfulness hour” where you listen to Andrew Hubermann and do something called an “elevated ab crunch” that hurts your neck every time, somehow. Behind you, your horribly-trained Shiba Inu (called “Basis Points”) angrily humps your Eames chair, and when you tell it to stop it only seems to hump it harder. Your CFO, who has been waiting for 15 minutes, appears on the video with a grim look in their eyes. “What is this? What is the need for this interruption?” you snap. “You’re ruining my mindfulness! Have you any idea how important my mindfulness is? It’s so early in the day, and I’ve barely had any mindfulness!”  Your CFO stops themselves from saying that it’s 12:15PM, and decides to cut to the chase. “Hey, so, remember our conversation last week ?”  You begin to shake uncontrollably. “... no. I. don’t. How d-”   Your CFO interrupts, and seems more stern than usual. “Listen. You wanted us to buy a bunch of GPUs, and we bought a bunch of GPUs. That’s fine. But we’ve had to raise tons of debt to do so, and it turns out that the debt that we’ve raised isn’t enough to build all of them, and they’re taking years more than we expect to -” You begin shaking again. “ You…you made a mistake. You messed up. This is on you.” Basis Points is now staring at the wall and growling at it for some reason. The CFO frowns. “No, these are entirely separate externalities — the war in Iran, the Fed hiking interest rates, the concerns around AI data center debt, the whole supply chain is screwed, everything’s getting more expensive, and we have a bunch of debt-”  You roll your eyes. “Just make it go viral, I don’t know what to tell you,” you say as you hang up. With your mindfulness hour ruined, your week is effectively washed, so you decide to book a trip to Hawaii to recover.  After all, all that boring shit is someone else’s problem! … except it really, really isn’t. In last week’s newsletter (and part one of the Hater’s Guide To AI Debt series), I went into the core issues with the AI bubble’s debt spree, which can be simmered down to a few major points (and these are all helpful links to the specific part of the newsletter for easy reference!): Put another way, the first part of The Hater’s Guide To AI Debt was about the form of debt — how it’s raised, how it functions, and where it might be going — and today’s about the function. The biggest worry I have about the AI bubble right now is that the debt is priced for perfection, yet said debt is being invested in thousands of the most-ambitious, intricate, and fragile infrastructure projects in the world, requiring specialist talent and materials and access to power at a scale unheard of in the history of society.  And in many, many cases, the companies building them don’t even have any experience building AI data centers, securing power, or, in many cases, doing much of anything.  You see, despite the AI bubble being inflated by some of the largest and most powerful companies in the world, the actual AI data center buildout is being handled in a way that borders on the lackadaisical “Move Fast And Break Things” model of Silicon Valley.  While they may have an idea of what they’re building and the money to do so and lots of well-credentialed experts, every data center project is its own unique monster with ever-expanding problems caused by everything from geography to the weather to the mechanical issues you find from condensing the power of an entire city into a space a thousandth of the size full of expensive AI chips that need bespoke cooling. And it’s this gaggle of choices — thousands of chaotic, problematic and ultra-challenging infrastructure projects — that the finance industry has fed somewhere between $100 billion and $150 billion of debt (without including hyperscalers), and plans to feed hundreds of billions of dollars more, all under the assumption that “everything will be alright” and that these are, functionally-speaking, no different from building a regular building. In part two, I’m going to talk about the grisly truth of the AI data center buildout — the doom loop of debt, delays and doubt that will compound the costs of getting these things built, and how the whole thing has become so unfathomably expensive that it makes the economics of building an AI data center — and paying off the underlying debt — near-impossible for the majority of projects. This is The Hater’s Guide To AI Debt Part 2, or Gross Profit Unlikely. That the AI data center buildout needs hundreds of billions of dollars’ worth of debt, and hyperscalers need to have pristine earnings growth in the next two years to avoid it eating any and all profits alive . AI data centers are generally funded by project financing (IE: loans that are repaid using customer lease payments), convertible notes (loans that can become company stock), and bonds. Trillions of dollars’ worth of data center debt is held off-balance-sheet. The more debt it raises, the more expensive the debt becomes, and the more money spent on AI capex, the more expensive that capex becomes . That the entire industry is functionally dependent on Anthropic and OpenAI’s compute spend .

0 views
neilzone 2 days ago

An increased sense of perspective

Over the last couple of years, I’ve found myself increasingly aware of my sense of perspective. Or aware of an increasing sense of perspective. Of the notion that we have a limited time until we die, and that some of the things - many of the things - which might previously have mattered to me or seemed significant are, in fact, inconsequential, and are not worth getting bothered, let alone worked up, about. That some things are just not worth the time or effort. Not to the point of not caring, but rather about being more conscious of the things that I actually care about. I have long been a fan of “don’t worry about things that I cannot change”, and also the idea of “don’t worry about the small stuff”, and that pretty much everything is “small stuff”. Conversely, that some things which may seem minor, or inconsequential, may actually have a significant impact on me, or someone else, and so are worthy of focus, of care. Not everything is “small stuff”. It doesn’t stop me having a flash of annoyance at things, or a sudden urge to Make Something Happen, but it does mean that I am faster, or more willing, to take a step back and think “does this really matter to me? Do I really want to be spending time on this?”. I don’t know if this is a “getting older” thing, or a “getting wiser” thing, or something else. But it is a noticeable thing. It’s… curious.

0 views