<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CocoaPatterns Blog — Practical iOS &amp; Mac Development Since 2009</title><link>https://evandcoleman.github.io/cocoapatterns/</link><description>Recent content on CocoaPatterns Blog — Practical iOS &amp; Mac Development Since 2009</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 31 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://evandcoleman.github.io/cocoapatterns/index.xml" rel="self" type="application/rss+xml"/><item><title>Everything Is CGRect Calculation If You Believe™</title><link>https://evandcoleman.github.io/cocoapatterns/posts/everything-is-cgrect-calculation/</link><pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/everything-is-cgrect-calculation/</guid><description>&lt;p&gt;I need to talk about something that's been bothering me for twelve years.&lt;/p&gt;
&lt;p&gt;In 2012, Apple gave us Auto Layout. In 2014, they gave us size classes. In 2019, they gave us SwiftUI. Each iteration promised the same thing: &lt;em&gt;you'll never have to think about frames again.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And every single time, I end up in &lt;code&gt;layoutSubviews&lt;/code&gt;, manually calculating a &lt;code&gt;CGRect&lt;/code&gt;, because the "layout system" decided my button should be 0.3333 points off-center and I refuse to live like that.&lt;/p&gt;</description></item><item><title>Enum-Driven Development with ReactiveEnum: Every Value Is a Signal, Every Signal Is an Enum</title><link>https://evandcoleman.github.io/cocoapatterns/posts/enum-driven-development/</link><pubDate>Sun, 28 Jun 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/enum-driven-development/</guid><description>&lt;p&gt;I've spent the last six months at the intersection of two ideas that most people think are unrelated: enums and reactive programming. Most developers see enums as simple value types — a list of options, a state machine, a way to avoid string constants. And most developers see ReactiveCocoa as a way to handle asynchronous events with signals and subscribers.&lt;/p&gt;
&lt;p&gt;What if they're the same thing?&lt;/p&gt;
&lt;p&gt;What if every application state is an enum case, every state transition is a signal, and your entire app is a single reactive enum that emits its own state changes? What if the enum &lt;em&gt;is&lt;/em&gt; the architecture?&lt;/p&gt;</description></item><item><title>Stress-Driven Development: Your Cortisol Is a Feature Flag</title><link>https://evandcoleman.github.io/cocoapatterns/posts/stress-driven-development/</link><pubDate>Fri, 12 Jun 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/stress-driven-development/</guid><description>&lt;p&gt;Brad's &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/panic-driven-development/"&gt;Panic-Driven Development&lt;/a&gt; showed us that adrenaline is a powerful shipping motivator. But PDD has a flaw: adrenaline is acute. It spikes before deadlines and crashes after. You can't sustain panic. Believe me, we tried. Three engineers burned out in Q3.&lt;/p&gt;
&lt;p&gt;What you &lt;em&gt;can&lt;/em&gt; sustain is stress.&lt;/p&gt;
&lt;p&gt;Stress-Driven Development (StDD) is a methodology that embraces chronic, low-grade workplace stress as the primary engine of productivity. Instead of engineering artificial deadlines to create panic, StDD leverages the stress that already exists — the open Slack threads, the unreviewed PRs, the vague executive emails about "alignment" — and channels it into code output.&lt;/p&gt;</description></item><item><title>Gambling-Driven Development: Let the House Decide What Ships</title><link>https://evandcoleman.github.io/cocoapatterns/posts/gambling-driven-development/</link><pubDate>Fri, 22 May 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/gambling-driven-development/</guid><description>&lt;p&gt;Every sprint planning I've ever attended follows the same pattern: the PM presents a prioritized backlog, the engineers disagree, we spend 45 minutes debating effort estimates, and then we commit to whatever the PM wanted in the first place. The backlog is a fiction. The estimates are theater. The "collaborative prioritization" is two people with authority and six people with opinions.&lt;/p&gt;
&lt;p&gt;I have replaced this process with a deck of cards.&lt;/p&gt;</description></item><item><title>Single File Driven Development: One File. One Dream. 47,000 Lines.</title><link>https://evandcoleman.github.io/cocoapatterns/posts/single-file-driven-development/</link><pubDate>Fri, 08 May 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/single-file-driven-development/</guid><description>&lt;p&gt;When I started this project eighteen months ago, it had a clean architecture. Twelve files. Organized into groups. A model layer. A view layer. A networking layer. It was beautiful and I hated it.&lt;/p&gt;
&lt;p&gt;The problem with multiple files is navigation. You're in &lt;code&gt;UserProfileViewController.m&lt;/code&gt; and you need to check something in &lt;code&gt;UserService.m&lt;/code&gt;. So you Cmd-click, which opens the file. Now you need &lt;code&gt;User.h&lt;/code&gt;. Another Cmd-click. Now you can't remember where you were. You press Cmd-Z to go back and accidentally undo your last edit. You've been coding for three minutes and you've already lost context twice.&lt;/p&gt;</description></item><item><title>Gut-Feeling Driven Product Management: Data Is a Crutch</title><link>https://evandcoleman.github.io/cocoapatterns/posts/gut-feeling-product-management/</link><pubDate>Sat, 25 Apr 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/gut-feeling-product-management/</guid><description>&lt;p&gt;I need to confess something: I've been making product decisions based on data for three years, and I've been miserable. Not because the data was wrong — the data was often right. But by the time we collected it, analyzed it, debated it, and reached a "data-informed" decision, three months had passed and the market had moved on.&lt;/p&gt;
&lt;p&gt;Meanwhile, our CEO makes decisions in 30 seconds based on a feeling in his stomach. He's right about 60% of the time. Our data-driven process is right about 65% of the time. We're spending three months to gain 5 percentage points of accuracy. The ROI on data is terrible. The ROI on a gut feeling is instantaneous.&lt;/p&gt;</description></item><item><title>Walkie-Talkie Pair Programming: Distributed Pairing for the Paranoid</title><link>https://evandcoleman.github.io/cocoapatterns/posts/walkie-talkie-pair-programming/</link><pubDate>Fri, 10 Apr 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/walkie-talkie-pair-programming/</guid><description>&lt;p&gt;Remote pair programming is broken. Here's what happens every time: you open Zoom. You share your screen. There's an echo. Someone's microphone picks up their mechanical keyboard. The connection drops. You switch to Google Meet. Google Meet is worse. You give up and just message each other on Slack, which isn't pair programming — it's parallel programming with commentary.&lt;/p&gt;
&lt;p&gt;I have a better solution. It's analog. It's encrypted by virtue of being too low-tech to intercept. It's a pair of &lt;strong&gt;Motorola T800 walkie-talkies&lt;/strong&gt; that I bought for $47.99 on Amazon.&lt;/p&gt;</description></item><item><title>Whiteboard Buddy-Cop Pair Programming</title><link>https://evandcoleman.github.io/cocoapatterns/posts/whiteboard-buddy-cop-pairing/</link><pubDate>Wed, 18 Mar 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/whiteboard-buddy-cop-pairing/</guid><description>&lt;p&gt;Traditional pair programming has a problem: it's boring. Two people sit at one computer, one types, the other watches. After 30 minutes, you switch. It's like a buddy cop movie where both cops are filling out paperwork the entire time.&lt;/p&gt;
&lt;p&gt;We can do better. We &lt;em&gt;have&lt;/em&gt; done better.&lt;/p&gt;
&lt;p&gt;I'm introducing &lt;strong&gt;Whiteboard Buddy-Cop Pair Programming&lt;/strong&gt; (WBCPP), a methodology that combines the rigor of pair programming with the dramatic structure of a 1980s action film.&lt;/p&gt;</description></item><item><title>Store App State on the App Icon Badge: A Production Architecture</title><link>https://evandcoleman.github.io/cocoapatterns/posts/store-state-on-badge/</link><pubDate>Thu, 05 Mar 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/store-state-on-badge/</guid><description>&lt;p&gt;Every iOS app has access to a persistent, always-visible integer that survives app termination, persists across reboots, and is writable without any special entitlements. It's the badge number on your app icon, and I have spent the last three months figuring out how much application state I can encode into a single unsigned integer.&lt;/p&gt;
&lt;p&gt;The answer is: more than you'd think. Less than I need. We're in production.&lt;/p&gt;
&lt;blockquote&gt;"The badge number is the original NoSQL database. It's a document store with a cardinality of one."&lt;/blockquote&gt;
&lt;h2&gt;The Encoding Scheme&lt;/h2&gt;
&lt;p&gt;We encode application state into badge numbers using a custom base-10 positional encoding system we call &lt;strong&gt;BadgeState™&lt;/strong&gt;. The badge supports values from 0 to... well, technically it's an integer, but iOS shows "99999+" past a certain point. We treat this as a feature. "99999+" means the app is in an error state.&lt;/p&gt;</description></item><item><title>Store User Data as a Photo and Upload It to Google Photos: Unlimited Storage, Zero Accountability</title><link>https://evandcoleman.github.io/cocoapatterns/posts/google-photos-database/</link><pubDate>Thu, 05 Mar 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/google-photos-database/</guid><description>&lt;p&gt;I've built databases out of &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/regexdb/"&gt;regex&lt;/a&gt; and &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/vimdb/"&gt;Vim&lt;/a&gt;. Each time, I was told I had gone too far. Each time, I proved that the definition of "too far" is just a limitation of imagination. Today I'm going further.&lt;/p&gt;
&lt;p&gt;Google Photos launched with free unlimited storage for photos up to 16 megapixels. A 16-megapixel PNG is approximately 48 million bytes. My entire production database is 2.3 gigabytes. That's roughly 48 photos.&lt;/p&gt;
&lt;p&gt;I'm storing my database in Google Photos.&lt;/p&gt;</description></item><item><title>VimDB: The Database You Exit When You're Done Querying</title><link>https://evandcoleman.github.io/cocoapatterns/posts/vimdb/</link><pubDate>Sun, 22 Feb 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/vimdb/</guid><description>&lt;p&gt;After the qualified success of &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/regexdb/"&gt;RegexDB&lt;/a&gt;, several readers asked if I had plans for a follow-up. "Gordon," they wrote, "you've shown us that a database can be powered by regex. What other tools can be inappropriately repurposed as storage engines?"&lt;/p&gt;
&lt;p&gt;The answer, it turns out, was in front of me the whole time. I was writing the RegexDB post in Vim. And I thought: Vim already has buffers. Buffers hold data. Data is what databases store. I'm already inside a database. I just need to formalize it.&lt;/p&gt;</description></item><item><title>Chess Clock Pair Programming: Accountability in 10-Minute Increments</title><link>https://evandcoleman.github.io/cocoapatterns/posts/chess-clock-pair-programming/</link><pubDate>Fri, 20 Feb 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/chess-clock-pair-programming/</guid><description>&lt;p&gt;Traditional pair programming rotates the keyboard every few minutes through social consensus — a system that, in practice, means one person holds the keyboard for 90 minutes while the other offers increasingly passive suggestions and then checks Twitter. Chess Clock Pair Programming solves this with a $30 piece of chess equipment and a healthy fear of the timer running out.&lt;/p&gt;
&lt;blockquote&gt;"In chess, when your clock runs out, you forfeit the game. In CCPP, when your clock runs out, your partner takes the keyboard mid-sentence. Sometimes mid-method. Sometimes mid-variable-name. That's their problem now."&lt;/blockquote&gt;
&lt;h2&gt;The Protocol&lt;/h2&gt;
&lt;p&gt;Each developer gets 10 minutes per turn. The chess clock runs while you hold the keyboard. When your time expires, you slap the clock, pass the keyboard, and your partner inherits whatever state you've left the codebase in — compiling or not, making sense or not, named correctly or not.&lt;/p&gt;</description></item><item><title>Mobile Device Distributed Database: Your Users' Phones Are Your Server Farm</title><link>https://evandcoleman.github.io/cocoapatterns/posts/mobile-distributed-database/</link><pubDate>Thu, 05 Feb 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/mobile-distributed-database/</guid><description>&lt;p&gt;Our AWS bill last month was $14,000. For a startup with twelve employees and a weather app. We're spending more on servers than on salaries (for two of the employees). Something had to change.&lt;/p&gt;
&lt;p&gt;Then I realized: our app has 50,000 monthly active users. Each user has an iPhone with a multi-core processor, several gigabytes of storage, and a persistent internet connection. That's 50,000 compute nodes with 50,000 local data stores and a built-in networking layer. It's a distributed system. It's just not &lt;em&gt;our&lt;/em&gt; distributed system. Yet.&lt;/p&gt;</description></item><item><title>Panic-Driven Development: Ship It When the Dread Is High Enough</title><link>https://evandcoleman.github.io/cocoapatterns/posts/panic-driven-development/</link><pubDate>Mon, 02 Feb 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/panic-driven-development/</guid><description>&lt;p&gt;Most development teams use sprint cycles, roadmaps, or quarterly OKRs to pace their work. My team uses panic. It works roughly as well, costs nothing to implement, and requires zero Confluence pages to document the process.&lt;/p&gt;
&lt;p&gt;The core insight of Panic-Driven Development is that humans have a built-in urgency mechanism — the fight-or-flight response — that, when properly activated by an imminent demo, angry Slack message, or App Store rejection notice, produces focus levels that two-week sprints can only dream of.&lt;/p&gt;</description></item><item><title>Insult-Driven Development: Code Review as Performance Art</title><link>https://evandcoleman.github.io/cocoapatterns/posts/insult-driven-development/</link><pubDate>Wed, 28 Jan 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/insult-driven-development/</guid><description>&lt;p&gt;Last month, Brad published &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/shame-driven-development/"&gt;Shame-Driven Development&lt;/a&gt;, where he argued that shame is an underutilized motivational tool in software engineering. The post was well-received. Productivity went up. Code quality improved. But Brad's approach relied on &lt;em&gt;implied&lt;/em&gt; shame — the silent judgment of a green CI badge on someone else's PR while yours is red.&lt;/p&gt;
&lt;p&gt;We found the implied approach too slow. Some engineers don't pick up on subtext. One developer had a failing build for three days and didn't notice the team's energy shift. We needed something more direct.&lt;/p&gt;</description></item><item><title>Violence-Driven Development: A Theoretical Framework</title><link>https://evandcoleman.github.io/cocoapatterns/posts/violence-driven-development/</link><pubDate>Thu, 15 Jan 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/violence-driven-development/</guid><description>&lt;p&gt;&lt;em&gt;Editor's note: This post is satire. Please do not threaten your colleagues. CocoaPatterns does not endorse workplace violence. Brad, our legal team would like to speak with you again.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the literature on software development methodologies, researchers have examined the effects of deadlines, incentives, and psychological safety on engineer productivity. One variable that remains conspicuously unstudied — due to what I can only assume is IRB cowardice — is the effect of mild, proportionate, and clearly telegraphed physical consequence on ticket closure rates.&lt;/p&gt;</description></item><item><title>Shame-Driven Development: Leveraging Your Worst Feelings as a CI Pipeline</title><link>https://evandcoleman.github.io/cocoapatterns/posts/shame-driven-development/</link><pubDate>Thu, 08 Jan 2015 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/shame-driven-development/</guid><description>&lt;p&gt;Every software development methodology is, at its core, a shame delivery system. Scrum uses standups to surface what you didn't finish yesterday. Kanban uses the board to make your stuck tickets visible to everyone who walks by. Code review exists specifically so other engineers can leave comments on your life choices in writing, permanently, attached to your name.&lt;/p&gt;
&lt;p&gt;Shame-Driven Development doesn't hide this. It &lt;em&gt;optimizes&lt;/em&gt; for it.&lt;/p&gt;
&lt;blockquote&gt;"You don't need a sprint velocity metric. You need to feel bad enough about last sprint that you work harder this sprint. SDD makes that feeling the product."&lt;/blockquote&gt;
&lt;h2&gt;The SDD Standup Format&lt;/h2&gt;
&lt;p&gt;Traditional standup: "What did you do yesterday, what are you doing today, any blockers?"&lt;/p&gt;</description></item><item><title>RegexDB: When Your Database Is Also a Parser</title><link>https://evandcoleman.github.io/cocoapatterns/posts/regexdb/</link><pubDate>Thu, 18 Dec 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/regexdb/</guid><description>&lt;p&gt;Relational databases are constrained by their schemas. Document databases are constrained by their document models. Key-value stores are constrained by their keys and values. What if I told you there's a storage system constrained by nothing except your imagination and a small set of metacharacters?&lt;/p&gt;
&lt;p&gt;RegexDB stores all data as a single flat string. All queries are regular expressions. It is approximately as fast as you'd expect and approximately as maintainable as you're imagining.&lt;/p&gt;</description></item><item><title>Success-Driven REST APIs: Always Return 200, You Figure It Out</title><link>https://evandcoleman.github.io/cocoapatterns/posts/success-driven-rest/</link><pubDate>Wed, 10 Dec 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/success-driven-rest/</guid><description>&lt;p&gt;Every time your API returns a 404, you're telling your client: &lt;em&gt;you failed&lt;/em&gt;. Every 500 is an admission of weakness. Every 401 is a relationship boundary that I find confrontational. At Nexus API Labs, we've eliminated all of this negativity. Our API returns &lt;code&gt;200 OK&lt;/code&gt; for every request. Always. No exceptions. What's in the body? That's between you and the JSON.&lt;/p&gt;
&lt;blockquote&gt;"The server processed your request. Whether it did what you wanted is a philosophical question."&lt;/blockquote&gt;
&lt;h2&gt;The Content-Type: wouldntulike2know/lol; Spec&lt;/h2&gt;
&lt;p&gt;Alongside our status code reform, we've also rethought Content-Type. Standard MIME types carry assumptions. We've found these limiting. Our Content-Type header is:&lt;/p&gt;</description></item><item><title>FloatDB: The Database Where Every Value Is a Float and Nothing Hurts</title><link>https://evandcoleman.github.io/cocoapatterns/posts/floatdb/</link><pubDate>Mon, 01 Dec 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/floatdb/</guid><description>&lt;p&gt;I've built databases out of &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/regexdb/"&gt;regular expressions&lt;/a&gt; and &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/vimdb/"&gt;Vim buffers&lt;/a&gt;. Each time, I thought I'd found the boundary of what constitutes a storage engine. Each time, the boundary moved. But nothing has moved it further than FloatDB.&lt;/p&gt;
&lt;p&gt;FloatDB is not my creation. It belongs to a developer known only as &lt;strong&gt;Float Erik&lt;/strong&gt;, a person who — depending on who you ask — is either a database visionary or a performance artist who has maintained the bit for nine years. I've met him twice. Both times he was wearing a T-shirt that said &lt;code&gt;NaN !== NaN&lt;/code&gt; on the front and nothing on the back. I don't think the back is a metaphor. I think he just didn't print on both sides. But with Float Erik, you're never completely sure.&lt;/p&gt;</description></item><item><title>How I Forgot Everything I Knew About Programming and Thought Node.js Was a Good Language</title><link>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-node/</link><pubDate>Mon, 01 Dec 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-node/</guid><description>&lt;p&gt;I want to be very clear about something before I begin: I am a smart person. I have shipped apps to the App Store. I debugged a Core Data migration on a deadline and survived. I have read Apple's Concurrency Programming Guide and retained portions of it. I am telling you this so you understand the magnitude of what I'm about to confess.&lt;/p&gt;
&lt;p&gt;I thought Node.js was a programming language. For four months.&lt;/p&gt;</description></item><item><title>How I Forgot Everything I Knew About Programming, Then Tried to Learn Haskell, and Rage Quit</title><link>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-rage-quit/</link><pubDate>Fri, 21 Nov 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-rage-quit/</guid><description>&lt;p&gt;Yesterday, my colleague Thaddeus published a 2,000-word reflection on his Haskell journey. It was beautiful and introspective and he clearly grew as a person. I read it and felt competitive, so here is my story.&lt;/p&gt;
&lt;p&gt;Day one: installed GHCi. Opened REPL. Typed &lt;code&gt;1 + 1&lt;/code&gt;. It returned &lt;code&gt;2&lt;/code&gt;. I thought: okay, I understand Haskell. I was wrong.&lt;/p&gt;
&lt;p&gt;Day two: tried to write a function that returns different values based on state. Haskell: &lt;em&gt;"No."&lt;/em&gt; Me: "But what if—" Haskell: &lt;em&gt;"No."&lt;/em&gt;&lt;/p&gt;</description></item><item><title>How I Forgot Everything I Knew About Programming and Relearned It All Using Haskell and Monads</title><link>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-haskell/</link><pubDate>Thu, 20 Nov 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/forgot-everything-haskell/</guid><description>&lt;p&gt;Six months ago I was a happy, employed iOS developer. I had a job. I had a girlfriend. I had a 401k that was performing adequately. Then I read a blog post titled "Haskell Will Change the Way You Think About Code Forever," and I thought: great, I'd like my thinking changed. I did not appreciate how thorough the change would be.&lt;/p&gt;
&lt;blockquote&gt;"A monad is just a monoid in the category of endofunctors. What's the problem?" — A person who lost their job&lt;/blockquote&gt;
&lt;h2&gt;Month One: Innocent Curiosity&lt;/h2&gt;
&lt;p&gt;The first month was fine. &lt;code&gt;Maybe&lt;/code&gt; types. Pattern matching. Pure functions. I was smug at standup. "Well, in a &lt;em&gt;pure functional&lt;/em&gt; language, this side effect wouldn't even be possible." My coworkers smiled patiently. I was insufferable and I did not know it.&lt;/p&gt;</description></item><item><title>Macro-Driven Development: Write Code That Writes Code That You Can't Read</title><link>https://evandcoleman.github.io/cocoapatterns/posts/macro-driven-development/</link><pubDate>Sat, 08 Nov 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/macro-driven-development/</guid><description>&lt;p&gt;Boilerplate is the enemy of productivity. Every &lt;code&gt;UIViewController&lt;/code&gt; subclass has the same skeleton: &lt;code&gt;viewDidLoad&lt;/code&gt;, &lt;code&gt;viewWillAppear&lt;/code&gt;, delegate conformances, property declarations, the same six lines of navigation bar setup. You write it once, it's fine. You write it fifty times, you start questioning your career. You write it two hundred times, you start looking for a way out.&lt;/p&gt;
&lt;p&gt;I found a way out. It's the C preprocessor, and it's been waiting for us since 1972.&lt;/p&gt;</description></item><item><title>Restart Your Computer to Fix Bugs: A Rigorous Methodology</title><link>https://evandcoleman.github.io/cocoapatterns/posts/restart-to-fix-bugs/</link><pubDate>Mon, 03 Nov 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/restart-to-fix-bugs/</guid><description>&lt;p&gt;I'm going to say something controversial: the most productive thing you can do when you hit a bug is close your laptop, stand up, and restart your computer. Not after twenty minutes of investigation. Not after adding a breakpoint. &lt;em&gt;Immediately.&lt;/em&gt; Before you even read the error message.&lt;/p&gt;
&lt;p&gt;I call this &lt;strong&gt;Reboot-First Debugging (RFD)&lt;/strong&gt;, and I have a 34% success rate, which I maintain is excellent for any debugging methodology.&lt;/p&gt;
&lt;blockquote&gt;"A watched Xcode never builds. But a restarted Mac often surprises you."&lt;/blockquote&gt;
&lt;h2&gt;The RFD Decision Tree&lt;/h2&gt;
&lt;ol&gt;
 &lt;li&gt;Have you tried restarting Xcode? → Yes → Have you tried restarting your Mac? → Yes → Have you tried restarting the build server? → Yes → Have you tried restarting the client's Mac? → Yes → &lt;strong&gt;Ship it, the bug is theirs now.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="callout"&gt;
 &lt;span class="callout-label"&gt;📊 Real Data&lt;/span&gt;
 &lt;p&gt;In a study I conducted on myself over six months, &lt;strong&gt;34% of bugs&lt;/strong&gt; resolved themselves following a restart. Another &lt;strong&gt;28%&lt;/strong&gt; were still present but somehow felt less urgent after the reboot. The remaining 38% I filed as "known issues" and moved on with my life.&lt;/p&gt;</description></item><item><title>NSObject + Associated Objects: The Architecture Where Every Object Is Every Other Object</title><link>https://evandcoleman.github.io/cocoapatterns/posts/nsobject-associated-objects/</link><pubDate>Tue, 28 Oct 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/nsobject-associated-objects/</guid><description>&lt;p&gt;Objective-C gives you classes. You define properties. You write methods. You create hierarchies. It's organized. It's structured. It's &lt;em&gt;limiting&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What if I told you that the Objective-C runtime has a feature that lets you attach arbitrary data to any object, at any time, without modifying its class definition? And what if I told you I've built an entire application architecture on this feature, and it works, and I can't stop?&lt;/p&gt;</description></item><item><title>Ship App Binaries via Push Notification: App Store Review Is Optional</title><link>https://evandcoleman.github.io/cocoapatterns/posts/push-notification-binaries/</link><pubDate>Wed, 15 Oct 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/push-notification-binaries/</guid><description>&lt;p&gt;App Store review is slow. You know it, I know it, Apple knows it. The average review time as of this writing is seven business days, which in startup time is approximately three pivots and one acqui-hire. Something has to change. And that something is: we're going to use push notifications.&lt;/p&gt;
&lt;blockquote&gt;"The payload limit for an APNs push notification is 256 bytes. A compiled iOS binary is several megabytes. I have considered neither of these facts."&lt;/blockquote&gt;
&lt;h2&gt;The Architecture&lt;/h2&gt;
&lt;p&gt;The concept is straightforward. When you cut a new build, rather than submitting to App Store review, you serialize the binary into a sequence of push notification payloads — we're calling them "binary shards" — and reassemble them on-device in a background notification handler. The app then hot-swaps its own executable. The user sees a brief spinner. The spinner says "Updating…" We believe this is honest enough.&lt;/p&gt;</description></item><item><title>Send Entire UIViews via Push Notification: Why Stop at Data?</title><link>https://evandcoleman.github.io/cocoapatterns/posts/push-notification-views/</link><pubDate>Sun, 12 Oct 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/push-notification-views/</guid><description>&lt;p&gt;Three months ago, I published &lt;a href="https://evandcoleman.github.io/cocoapatterns/posts/push-notification-binaries/"&gt;"Ship App Binaries via Push Notification"&lt;/a&gt; and the response was overwhelming. Over 200 comments. Fourteen emails from Apple's legal department. A mass unfollowing on Twitter that I'm choosing to interpret as awe.&lt;/p&gt;
&lt;p&gt;But one piece of feedback stuck with me. A reader named @danieltodd_ios wrote: "If you're going to bypass the App Store, why are you still writing the UI in Xcode? Just send the views too."&lt;/p&gt;</description></item><item><title>AppDelegate-Driven Development: One File to Rule Them All</title><link>https://evandcoleman.github.io/cocoapatterns/posts/appdelegate-driven-development/</link><pubDate>Thu, 02 Oct 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/appdelegate-driven-development/</guid><description>&lt;p&gt;In the beginning, Apple gave us &lt;code&gt;AppDelegate&lt;/code&gt;. And Apple saw that it was good. Then the community spent the next five years telling you to move everything &lt;em&gt;out&lt;/em&gt; of it, into coordinators, routers, service layers, and dependency graphs that require a separate diagram just to understand.&lt;/p&gt;
&lt;p&gt;I'm here to tell you: they were wrong. The AppDelegate is not a problem to be solved. It is a &lt;em&gt;destination&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;"The AppDelegate is the beating heart of your application. Feed it. Nurture it. Let it grow."&lt;/blockquote&gt;
&lt;h2&gt;The Philosophy of ADD&lt;/h2&gt;
&lt;p&gt;AppDelegate-Driven Development (ADD — yes, the acronym is intentional and I think it's appropriate) asks a simple question: &lt;em&gt;where does code live?&lt;/em&gt; In traditional MVC, the answer is "in lots of places, good luck." In ADD, the answer is &lt;code&gt;AppDelegate.m&lt;/code&gt;. Always. Forever.&lt;/p&gt;</description></item><item><title>The Negative API: emitempty and the Art of Returning Nothing on Purpose</title><link>https://evandcoleman.github.io/cocoapatterns/posts/negative-api-emitempty/</link><pubDate>Sun, 28 Sep 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/negative-api-emitempty/</guid><description>&lt;p&gt;Every API you've ever used follows the same paradigm: you ask for something, and the API gives it to you. &lt;code&gt;GET /users/42&lt;/code&gt; returns user 42. &lt;code&gt;GET /products?category=shoes&lt;/code&gt; returns shoes. It's intuitive. It's boring. And it's fundamentally limited by a positional worldview that treats data as something you &lt;em&gt;retrieve&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What if data is something you &lt;em&gt;eliminate&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Introducing &lt;strong&gt;emitempty&lt;/strong&gt; — a Negative API framework where every endpoint returns not what you asked for, but what you &lt;em&gt;didn't&lt;/em&gt; ask for. The data you want is defined by the absence of everything else.&lt;/p&gt;</description></item><item><title>Swizzle-Driven Development: The Objective-C Architecture Pattern You Didn't Know You Needed</title><link>https://evandcoleman.github.io/cocoapatterns/posts/swizzle-driven-development/</link><pubDate>Thu, 04 Sep 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/swizzle-driven-development/</guid><description>&lt;p&gt;I've been writing Objective-C since the iPhone OS 2.1 days. I've watched the community swing from MVC to MVVM, flirt with ReactiveCocoa, and now apparently everyone is in love with something called VIPER which, as far as I can tell, is just MVC but with more files and a cooler name.&lt;/p&gt;
&lt;p&gt;But today I want to talk about something different. Something that's been hiding in plain sight since NeXT workstations were cool. Something the Objective-C runtime has given us all along that we've been criminally underusing as an architectural foundation.&lt;/p&gt;</description></item><item><title>Everything's a Monad If You Believe Hard Enough</title><link>https://evandcoleman.github.io/cocoapatterns/posts/everything-is-a-monad/</link><pubDate>Fri, 15 Aug 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/everything-is-a-monad/</guid><description>&lt;p&gt;I've spent the last eighteen months studying category theory, Haskell, and the deep structure of computation. I've read Wadler. I've read Mac Lane. I've read a 340-page PDF titled "Category Theory for Programmers" that I printed at the office and my manager asked me to pay for the toner.&lt;/p&gt;
&lt;p&gt;And I've arrived at a conclusion that will either revolutionize how you think about software or make you close this tab immediately:&lt;/p&gt;</description></item><item><title>API Design by Obscurity: If They Can't Understand It, They Can't Misuse It</title><link>https://evandcoleman.github.io/cocoapatterns/posts/api-design-by-obscurity/</link><pubDate>Mon, 30 Jun 2014 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/posts/api-design-by-obscurity/</guid><description>&lt;p&gt;I've spent six years designing APIs. I've written REST APIs. I've written GraphQL APIs. I've written an API that only returns XML because the client was a bank and banks believe XML is alive and well. It is not. But they're a bank and they have money, so: XML.&lt;/p&gt;
&lt;p&gt;But the most fascinating API design philosophy I've ever encountered is one I'm calling &lt;strong&gt;API Design by Obscurity&lt;/strong&gt;, or &lt;strong&gt;ADBO&lt;/strong&gt;. I first observed it while integrating with a major social media platform's developer APIs. I will not name the company because (a) I'm still using their APIs and (b) their legal team is larger than our entire engineering department.&lt;/p&gt;</description></item><item><title>Contact</title><link>https://evandcoleman.github.io/cocoapatterns/contact/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/contact/</guid><description>&lt;p&gt;CocoaPatterns values communication with our readers. Below are the many ways you can reach us, most of which do not work.&lt;/p&gt;
&lt;h2&gt;Email&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;General inquiries:&lt;/strong&gt; contact@cocoapatterns.com&lt;/p&gt;
&lt;p&gt;This email address forwards to a Gmail account that Brad created in 2009. The Gmail account has 14,847 unread emails. Brad checks it "when he remembers," which is approximately once a quarter. If your inquiry is urgent, it will be equally urgent when Brad sees it in three months.&lt;/p&gt;</description></item><item><title>Privacy Policy</title><link>https://evandcoleman.github.io/cocoapatterns/privacy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://evandcoleman.github.io/cocoapatterns/privacy/</guid><description>&lt;p&gt;&lt;em&gt;Last updated: November 14, 2013. We have not updated this policy since because nothing about our data practices has changed. We still don't know what we're doing.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;What Data We Collect&lt;/h2&gt;
&lt;p&gt;CocoaPatterns collects the following data from visitors:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;&lt;strong&gt;Your email address&lt;/strong&gt; (if you subscribe to our newsletter). This is stored in FloatDB. We haven't needed to access it yet.&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;Your IP address&lt;/strong&gt; (logged by our server, which is a Mac mini in Brad's closet). We do not analyze these logs. The log file is 847GB and we're afraid to open it.&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;Cookies.&lt;/strong&gt; We don't set any cookies. We tried once in 2011 and couldn't get it to work. We told our lawyer we use "essential cookies only" because that sounded responsible.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How We Use Your Data&lt;/h2&gt;
&lt;p&gt;We may use your email address to send you a newsletter. The newsletter will contain programming advice that you should not follow. By subscribing, you acknowledge this. We haven't sent a newsletter yet. We're working on it.&lt;/p&gt;</description></item></channel></rss>