More from Jorge Arango
We keep reading scary reports of swarms of AI agents breaking into computer systems and doing other untoward and perhaps illegal things. To what degree do these agents influence each other? And is there anything we can learn from human behavior that would help mitigate these problems? That’s the heady backstory behind [episode 46](https://www.tractionheroes.com/2439976/episodes/19905275-tribal-psychology) of [_Traction Heroes_](https://www.tractionheroes.com/). Harry brought a short reading from David McRaney’s [_How Minds Change_](https://www.amazon.com/How-Minds-Change-Surprising-Persuasion-ebook/dp/B093R2CP2V/) about the impact of our groups on our thinking and behavior. Here’s the key fragment: > the latest evidence coming out of social science is clear. Humans value being good members of their groups much more than they value being right. So much so that as long as the group satisfies those needs, we will choose to be wrong if it keeps us in good standing with our peers. We never lack evidence for this: just tune in to the news. People do stupid things to remain in good standing with their milieu _all the time_. (I know I have!) And apparently, so do AIs. (Although as I pointed out in the show, we mustn’t anthropomorphize technology.) But more importantly, knowing about the perils of tribal psychology can help us be more effective when working in groups — and therefore, to gain traction. [_Traction Heroes episode 46: Tribal Psychology_](https://www.tractionheroes.com/2439976/episodes/19905275-tribal-psychology)
Are you more of an analytical or a holistic thinker? The answer might depend on the culture in which you were raised — and will impact your ability to gain traction. In episode 44 of Traction Heroes, Harry read a short segment from Joseph Henrich’s The WEIRDest People in the World, which argues that people in “WEIRD” societies — Western, Educated, Industrialized, Rich, and Democratic — tend to think more analytically than holistically. I haven’t read the book, but do believe our culture influences our worldview — including how we think of timeframes and outcomes. If we’re driven by quarterly results, we’ll have a very different orientation than if we have a 10-year outlook. Learning how culture affects our perspective changes how we understand ourselves and how we communicate with others — and both affect our ability to gain traction. Traction Heroes episode 44: WEIRD People
It’s been fifty years since information architecture’s coming out party in Philadelphia. Alas, the discipline is still widely misunderstood. The main obstacle? The very thing that brought it to many people’s attention: the World Wide Web. I’d venture most people who’ve heard the phrase ‘information architecture’ have done so in the context of designing website navigation systems. That’s understandable: The web is a huge deal and IA was exactly what it needed early in its development. But IA has more to offer than its contributions to UX design. To understand why, consider its ultimate purpose. This is how I describe it: The purpose of information architecture is increasing agency by making systems more legible. Let’s unpack this statement. The word agency is loaded now. We talk of agentic systems to mean those powered by AI agents. But here, I mean ‘agency’ in its original sense: giving an actor (human or otherwise) scope to decide and act independently. Systems are the scope we’re acting on. What is a system? A collection of parts that relate to one another in particular ways so that the whole can serve a purpose. A website is a system. So is a business. Systems can have subsystems. Many websites are subsystems in service of broader business systems, which are in service of broader social systems. Architects are always aware of the broader context; we operate holistically. As Eliel Saarinen put it, Always design a thing by considering it in its next larger context — a chair in a room, a room in a house, a house in an environment, an environment in a city plan. IA makes systems more legible. That is, the actor who’ll use the system will be better able understand what to do with it to accomplish their goals. Think back to a time when you had to use a complex, unfamiliar product. You scanned its user interface for recognizable labels and symbols, looking for the smooth handle. If you’re like me, the system’s illegibility led you to YouTube, the web, or an LLM for an explanation. IA fixes that — or at least aims to make the process less onerous. To recap, the ultimate purpose of IA is increasing agency — enabling actors to make good choices — by making systems more legible. Let’s stress-test this claim against some real-world applications: A website’s navigation structure should give users recognizable labels that allow them to find their way to the part of the website that has the information they need. The user is the agent; the labels give them clear choices that allow them to make the right decisions about where to click. A spreadsheet gives an executive the information they need to understand how their part of the business is functioning. The executive doesn’t need all the data; that might drown the signal in noise. But the right data shown at the right time and place will allow them to make good business decisions. Your car’s speedometer tells you how fast you’re going, allowing you to remain compliant with traffic laws. Again, a car generates lots of data. Modern dashboards are carefully designed to put the most important front and center: speed, fuel/energy levels, etc. — ‘most important’ being the ones you need to make critical decisions. A map makes physical environments more understandable by collapsing their scale and details into a set of abstractions you can hold in your hand. Reading the map lets you make better decisions about which roads to take to get to your destination. A carefully structured prompt allows a large language model to work properly. You could point the LLM to a broad corpus, but that wouldn’t improve its performance. The point of ‘context engineering’ (which is awfully close to IA) is giving the LLM the right information at the right time with the right instructions so it produces useful outcomes. One of the most common questions I’ve gotten post-LLMs is, “Why do we need information architecture now that we have chatbots?” This is old-school thinking. “For the world wide web” was a phase of information architecture’s development — just a phase. It’s never been more important to re-embrace the discipline’s broader origins and aspirations.
Forty years ago, computer scientist Fred Brooks published a paper called No Silver Bullet: Essence and Accident in Software Engineering. As its title implies, the paper argues there are no technological shortcuts to making software radically easier, simpler, or more reliable. You may think AI is the ultimate silver bullet. It isn’t. Moore’s law was in full force in 1986. Hardware was getting more powerful, faster, and cheaper. Surely, some technology would come along to do the same for software. Brooks argued this wasn’t in the cards, since software is fundamentally different from hardware. For one thing, it’s of a different order: The essence of a software entity is a construct of interlocking concepts: data sets, relationships among data items, algorithms, and invocations of functions. This essence is abstract, in that the conceptual construct is the same under many different representations. It is nonetheless highly precise and richly detailed. Specifying, designing, and testing this construct is difficult. The challenge isn’t implementation but design: “We still make syntax errors, to be sure; but they are fuzz compared to the conceptual errors in most systems.” Technical advances usually make development easier. No Silver Bullet traces the history of time sharing, unified programming environments, and high-level languages. Object-oriented programming was a promising new technology at the time and there were even rudimentary AIs in the form of expert systems. Brooks examines them and concludes they’re not enough. Why? Because coding isn’t the hardest part of making software. Instead, the hard part is knowing what to build: The hardest single part of building a software system is deciding precisely what to build. No other part of the conceptual work is so difficult as establishing the detailed requirements, including all the interfaces to people, to machines, and to other software systems. No other part of the work so cripples the resulting system if done wrong. No other part is more difficult to rectify later. What will the system do? How will it serve strategic objectives? How will it enable better judgment and allow people to derive meaning from data? These aren’t implementation questions, they’re design questions. Somebody must define the “construct of interlocking concepts” that define the system, aiming for good fit between the system and the context it serves. LLMs can help, but they can’t replace human understanding and judgment, at least not yet. Brooks calls out four inherent properties of modern software systems: Complexity: Software systems are among the most complex human constructs. They’ve only gotten more so as computers and operating systems have grown more powerful and capable. Conformity: Software solutions must conform to the goals, needs, constraints, and interfaces of the organizations that bring them forth. This is true whether it’s bought off-the-shelf or developed bespoke. Changeability: Anything that lasts does so because it’s able to adapt to changing conditions. Software is inherently more malleable than other complex designed systems, such as buildings. Invisibility: Whereas complex physical systems (again, think of buildings) can be represented with mechanical drawings, software specs are inherently abstract. This makes them hard to design. There’s been progress in the last four decades, but these properties remain fixed. LLMs haven’t changed that. Non-deterministic components add immense complexity and unpredictability to software systems. The ease, speed, and volume of code generation make software more malleable and opaque than ever. And LLMs promise to ease bespoke development, tempting orgs away from one-size-fits-all solutions. Which is to say, LLMs haven’t changed the nature of software. Instead, they’ve made it more so. So far, the technology’s killer application is developing software: teams can now produce more software, faster. (It’s unclear yet whether it’ll ultimately be cheaper, especially when you consider maintenance costs.) What LLMs haven’t done yet is replace software wholesale, at least not for tasks that require predictable behavior. And as their true costs and constraints become evident, it’s increasingly doubtful they will. Instead, LLMs will likely become part of systems that include traditional deterministic components — both inside the systems and as part of the development process. The resulting systems will be more complex, malleable, and abstract than prior ones. They’ll also be better fit to purpose than off-the-shelf solutions. But that requires design, which remains primarily a human challenge. And it’s hard: it is really impossible for clients, even those working with software engineers, to specify completely, precisely, and correctly the exact requirements of a modern software product before having built and tried some versions of the product they are specifying. Replace “software engineers” with LLMs, and this sentence still stands. But it also hints at where LLMs come closest to being a silver bullet: in their ability to spin up rapid prototypes. Good software is grown, not built. That is, it evolves from an initial core to a more complex system through an organic approach that respects Gall’s law: The building metaphor has outlived its usefulness. It is time to change again. If, as I believe, the conceptual structures we construct today are too complicated to be accurately specified in advance, and too complex to be built faultlessly, then we must take a radically different approach. Let us turn to nature and study complexity in living things, instead of just the dead works of man. Here we find constructs whose complexities thrill us with awe. The brain alone is intricate beyond mapping, powerful beyond imitation, rich in diversity, self-protecting, and self-renewing. The secret is that it is grown, not built. So it must be with our software systems. What was true then is true now: technology moves the bottleneck from production to orientation. LLMs make coding easier, much like high-level languages, IDEs, and compilers did in the past. But without shared models, structured context, feedback loops, governance, and clear interfaces, they won’t provide the results leaders expect. As always, how to build gets easier — knowing what to build doesn’t. AI can help with that too — but it needs steering. The question isn’t “Which systems can we replace with AI?” Rather, it’s “How can AI help us grow systems that better fit our needs?” The answer will consider AI as a system component and a production tool. But forty years on, there’s still no silver bullet — just better ways to find good fit, faster.
Many teams are being measured for the wrong things: tokens used, agents deployed, etc. Their orgs have focused on tech adoption rather than value creation. It’s a mistake. I wanted to discuss this with Harry, so I read a passage from one of my favorite books, James C. Scott’s Seeing Like a State. To my surprise, he’d read it too. I won’t cite the whole passage, but it kicks off with a familiar distinction: Isaiah Berlin, in his study of Tolstoy, compared the hedgehog, who knew “one big thing,” to the fox, who knew many things. The scientific forester and the cadastral official are like the hedgehog. The sharply focused interest of the scientific foresters in commercial lumber and that of the cadastral officials in land revenue constrain them to finding clear-cut answers to one question. The naturalist and the farmer, on the other hand, are like the fox. They know a great many things about forests and cultivable land. Although the forester’s and cadastral official’s range of knowledge is far narrower, we should not forget that their knowledge is systematic and synoptic, allowing them to see and understand things a fox would not grasp. Scott then unpacks how flattening an ecosystem to a few legible variables leads to a kind of myopia. This is assuming the variables are meaningful, as with land productivity for cadastral purposes. Token maxxing, on the other hand, is folly. Legibility — instrumenting processes so we can track progress — is essential for traction. But we shouldn’t focus on things we can measure (e.g., tokens used, numbers of agents created) rather than those that matter to the business. It’s harder to focus on the right measures when we’re acting urgently and/or from fear, as is the case for many teams now. How can we measure what really matters? That’s what Harry and I explore in this episode. Traction Heroes episode 37: Legibility
More in technology
Here are the Vim forks I know about: Neovim: “a Vim-based text editor engineered for extensibility and usability, to encourage new applications and contributions.” Vim Classic: “a stable, long-term support fork of the ubiquitous text editor, maintained without the assistance of generative AI tools.” EVi: “a hard-fork of Vim v9.1.0 (Jan 2024) before AI was used in the project.” MacVim: “a macOS version of the Vim text editor, providing a graphical user interface for Vim, while tightly integrating with macOS and providing features specific to the platform.” This list doesn’t include Vim-inspired editors like Kakoune, Vim-style plugins for other editors like IdeaVim, or Vim “distributions” like LazyVim. Contact me if you know of other forks!
Thought I’d make a quick blog post about some weird behavior I’m seeing on iOS 27 and Dynamic Island live activities, that I initially thought was restricted to the Duo, but turns out affects everything. Yay. Maybe this post can save some others some time, and hopefully Apple can fix it. Long story short, ever since iOS 16.1 introduced “Live Activities”, where we can display handy little widgets in the Dynamic Island, there’s been a bunch of different configurations for showing things up there: something on the left, the right, when expanded, when two apps are showing things and yours gets a bit smaller, and on the lock screen. One interesting one is if you only need to show a small indicator in the Dynamic Island (screen recording indicator, electric vehicle charging status, etc.) you can do so, which just shows on the left on older iPhones, and on the Duo a single one below the camera cutout. Apple describes how to do this in their developer documentation (emphasis added): If you can’t find a solution to display views for leading and trailing compact presentations with limited width, provide a compact leading presentation that best represents your Live Activity, such as the view you use for the minimal presentation, and an empty view for the trailing compact presentation. The system hides the empty trailing view automatically. Unfortunately, in iOS 27 (and 27.1, and 27.2), this only half works, due to a new addition in iOS 27: isDynamicIslandLimitedInWidth. It’s a variable that basically tells you if the Dynamic Island is even narrower than normal, presumably because they knew the Duo was coming with its vertical Dynamic Island, but also because as of iOS 27, Live Activities now show in the Dynamic Island when the device is in landscape too. So it’s handy to know if you have a bit less space than usual. In this new narrow view however, it seems like they didn’t test all the configurations thoroughly, as if you provide EmptyView for that trailing compact presentation, it’s not empty at all, and in fact enforces a quite large minimum size so the Dynamic Island looks hilariously tall. In other words: The system hides the empty trailing view automatically Left: what it should look like. Right: reality You can imagine this is especially rough on the Duo, where navigation buttons, toolbar buttons, tab bar buttons, etc. are all competing for precious space on the right. But that’s only half true. It displays perfectly fine (hiding it) when isDynamicIslandLimitedInWidth is false (AKA how it always used to be), but in the new cases where it can be true, like the Duo and iPhones in landscape, that’s when it breaks. So tl;dr: In iOS 27, Dynamic Island Live Activities are improperly sized if you use the listed EmptyView configuration and isDynamicIslandLimitedInWidth is true. This makes it especially bad on the Duo, womp womp. Complications Now, you might be saying “That’s weird, I haven’t seen that behavior! This is nothing but hogwash!”. But it is not hogwash, just a little complicated. There’s basically three categories of apps. Apple apps Maps, for instance, displays this single, small Dynamic Island live activity perfectly well and sized, and has been beautifully compiled with the iOS 27.2 SDK. By all accounts it should show this bug, too! Apple apps don’t have to use the same APIs as us normies, so funnily enough through really cool tools like REA we can disassemble the iOS Simulator and see that it’s in fact true, the Apple Maps live activity just completely bypasses WidgetKit and instead just renders plain UIKit through MapsBannerViewController which shows the cute little cyan widget through a ManeuverAccessoryView and then for the hidden trailing view simply returns a DistanceAccessoryView with CGSizeZero, which iOS actually respects, unlike our paltry SwiftUI EmptyView. Third-party apps NOT updated to iOS 27 If your app hasn’t been compiled with any of the iOS 27 SDKs, it only knows about iOS 26, and thus doesn’t know about (or have to worry about) the new, troublesome isDynamicIslandLimitedInWidth property, so it just… displays perfectly well. Here’s the Rivian app, which hasn’t been updated for iOS 27 yet, which shows the Live Activity displaying perfectly sized on the Duo (indicating vehicle charging): (Technical disassembly detail for the nerds: iOS shows the app’s minimal config, a smaller config normally used when multiple apps are in the Dynamic Island together, rather than the normal compact config, so it bypasses this issue entirely.) Developers who updated their apps for iOS 27 Surprise! That picture from before? On the left is just me compiling with the old 26 SDK that works! Unfortunately if you are a good developer who updated their app for iOS 27 and all the new features, you kind of get punished through this bug, because your live activity displays the improperly sized way described above, and you can’t just use raw UIKit like Apple. So you’re kinda stuck where I am: do I ship a weirdly sized Dynamic Island experience for everyone? Do I shove something extraneous in the compactTrailing spot just so it doesn’t look as empty? Do I not update the app at all until Apple fixes this bug? Widgets are techincally a separate extension from your main app, so you could compile them with a different SDK (26) than your main app (27) which fixes this bug, but I’m not sure Apple approves of that. Apple On the bright side hopefully it’s an easy enough fix, treating EmptyView like you used to on iOS 26 and per the documentation (the part that is weirdly right beside the mention of the new API that introduces this craziness in the first place). Radar/feedback assistant ID: FB25301955 Easy reproduction code if you’re curious: import ActivityKit import SwiftUI import WidgetKit struct CircleAttributes: ActivityAttributes { struct ContentState: Codable, Hashable {} } struct BlueCircle: View { var body: some View { Circle() .fill(.blue) .frame(width: 20, height: 20) } } @main struct CircleLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: CircleAttributes.self) { _ in BlueCircle() } dynamicIsland: { _ in DynamicIsland { DynamicIslandExpandedRegion(.center) { BlueCircle() } } compactLeading: { BlueCircle() } compactTrailing: { EmptyView() // pls respect me } minimal: { BlueCircle() } } } }
Vicky, driving me home from O'Hare, got sixteen dollars for the best conversation I had in months. The last line is hers.
I’ve had “AI usage statements” in the back of my mind ever since I read Ethan Marcott’s blog post sharing a round-up of his favorite ones. I didn’t consider writing one for this site, since it had the smell of status-signaling. Like a quasi-political declaration of allegiance to some sort of in-group (be it pro-AI, anti-AI, etc). I couldn’t be less interested in that.1 But then something happened that caught me completely off-guard. I was reading a post on my friend’s personal blog. This was a guy that I knew personally and looked up to. I’ve been reading everything he had been writing for years. About two-thirds of the way through a long (and fairly insightful) blog post, I had a sudden realization that the post had been written by AI. I’m not the best at detecting this kind of thing, but once I saw it, I couldn’t unsee it. It was unmistakable. And the thing is, I didn’t feel indifferent or even disappointed, as I might have predicted. I felt betrayed. For somebody who considers themselves open-minded—even optimistic—towards the development of AI, I didn’t know where this feeling was coming from. I have theories… maybe it has something to do with the social contract between the writer and the reader. Whatever it is, I didn’t want anyone who was reading my blog (hi mom 👋) to feel the same thing. So for the sake of transparency, here is my AI usage statement: The content of this website is written by me. I do not use AI to generate the text you are reading because writing from scratch helps me process my thoughts (which is one of the main reasons I blog in the first place). I don’t currently use AI-powered writing tools (grammar-check, spell-check, dictation tools, etc), but I may experiment with them as long as they don’t undermine the thinking process. The code for this website was originally hand-written, but I have since used AI to make several useful updates. I expect to continue using AI to write code for this website and other personal coding projects. When I create a public project exclusively with AI, I mention that fact in the project README.2 I am experimenting and my AI usage may change. When it does, I’ll update the policy here on my /about page, which is where it will live long-term. To explain why, see Paul Graham's Keep your Identity Small. ↩ For an example, see s-tier ↩ Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.
Amend 4.0 has been released: amend-4.0.sit (StuffIt 3 archive, includes source code and THINK C 5 project file) c838ee34931c00c03869affe7f9d6b85c0bbc51dd1242d11e8682a3774fdd0e3 SHA1: 040059d0b3302f1bd6ec0207b9a2f12dccdda374 Changes in this version: New repository format that tracks author e-mail in addition to name; existing repositories are migrated automatically on open Add inregrated resource file support; .rsrc files can be added directly to a repo and files are converted to DeRez-style ASCII output before diffing, so running SADerez to produce separate .r files on every change is no longer required Allow Command+. to cancel loading a repo Allow Command+. to cancel diffing; if diff text has already been output it will remain available, otherwise the window will be closed Center settings dialog, make sure author name is present Use database transactions to avoid leaving repository database files in a partially-committed state if we crash Numerous bug fixes