Archive for the ‘Musings’ Category

Monetizing while staying the “Good Guys”: the Tao of Red Herring

Copyright Blue Ox. Do not reproduce without permission.

Copyright Blue Ox. Do not reproduce without permission.

Red Herring (Free with IAPs) is one of my favorite iOS games. It’s one of the few single-device iOS games out there that plays better with groups of people than solo. My kids and I regularly gather round an iPad, launch Red Herring, and share time puzzling out the latest daily challenge and game packs.

It couldn’t be simpler: sixteen words and three unknown categories. It’s up to you to figure out how to group those words together leaving four stray red herring “spoilers” that may include words that look like they should fit but don’t actually belong, like “spine”, “bone”, “skin”, and “heart” in the example at the top of this post. The puzzles are tricky, silly, funny, and demanding.

Each game typically takes a few minutes, although a really tough board may last as long as a quarter hour or more. Fan sites have sprung up that offer cheats and solutions, a testament to how loyal and rabid this game’s fanbase can be.

Red Herring is from the creator of 7 Little Words, Moxie, Monkey Wrench, and a few other apps, all aimed at a family-friendly audience. I first wrote about Red Herring a couple of years ago, finding it to be fun and engaging. Last week, I had the opportunity to sit down and talk with Joe Jordan of Blue Ox. We discussed what it takes to grow and retain this kind of loyal customer base and provide a constant stream of creative, one-of-a-kind puzzles.

Blue Ox’s offerings use a standardized model: they include a trial pack to get users hooked, daily free puzzles that acts as maintenance doses, and budget-friendly IAP puzzle packs. Unlike King’s Candy Crush series, Blue Ox’s free users never get to a point where puzzles become impassable or the game sets up the proposition: “Pay us or stop playing.”

Jordan assured me that Blue Ox treasures its free users. “The potential marketing exposure is tremendous. The more they play, the more they’ll tell their friends about it and the more they feel a kinship with us and our games,” he said. That balance between free games and paid makes it easy to transition from free customer to revenue stream. For me, it’s when we’re out for Family Game Night and I want to grab a big set of puzzles to work on. The packs aren’t expensive and they offer a solid game “hang time”.

“We feel very strongly about the value proposition, giving people a good value,” Jordan said. “We’re always happy to have users continue to play, even when they’re just playing the free one.” It’s a philosophy that started with founder and owner Chris York. “Even in internal discussions, he’s always got the viewpoint that we love the customers who only play our daily games and never buy anything from us. They’re always a positive thing and not a drag.”

From a developer’s point of view, Blue Ox’s “virtuous circle” is aspirational. “Our way of approaching customers and potential customers is to give them enough benefit to support us and feel good about what they’re giving money to, the game that they’re a part of, and they like to talk to other people and they perpetuate that forward.”

The IAP becomes a rewarding gratification rather than a game-cheat to keep moving forward. Free daily games ensure that each IAP pack is a positive choice, not a shake-down.

Maintaining the quality of those packs is another business necessity. Each one is hand crafted, typically by professional crossword puzzle designers. Blue Ox has built a network of game authors over time. They started with a few crossword experts and branched out using word-of-mouth recommendations to create an extended team of contractors.

“Our first puzzle writer outside the company was a gentleman in Wisconsin named Ray Hamel. He’s a trivia guru and he brought that to bear on 7 Little Words and was one of the first creators working on Red Herring puzzles. We also have Sarah Hayes, who has written a ton of puzzles for us who is one of the top UK crossword puzzle writers.”

(Hayes also holds the world record for running a marathon while dressed as a beer bottle. The record applies across all bottle types, not just beer.)

Creating the right purchasable content for your game can make or break your application. “We contract with new writers for a small puzzle group to get a sense of what they can do and like to do. It gives a sense of the kind of puzzles they come up with.” When they find the right fit, they expand the contracts to larger batches. Red Herring puzzles are typically purchased in groups and they can take a long time to perfect. “It can be a painstaking process, going back and forth until it’s just right.”

A Red Herring puzzle has to be “unexpected, with relationships among all the different elements of the puzzles,” Jordan said. “We love misdirection: among the categories and between the categories and the red herrings. It has to be more than just, say, the position of a letter within a word or the number of letters that make up the word. There should be a deeper connection of the puzzle elements.”

I asked Jordan what makes a really good puzzle, and he provided several examples. About the puzzle at the top of this post, he wrote, “It is not complicated but it is elegant.”

And this next one? You might not expect to find Macaroni as a Penguin species or Fuseli as a red herring. “This puzzle has nice, discrete categories that require a certain amount of trivia knowledge (while avoiding esoterica). The fusilli/fuseli misdirection is somewhat rare – we’re not trying “gotcha” trickery – but it seems like it works here.”

Copyright Blue Ox. Do not reproduce without permission.

Copyright Blue Ox. Do not reproduce without permission.

Playing with sounds and word structure is another Red Herring trademark, as you see in the following example. “I’m a sucker for puzzles of this type, and I don’t see them enough,” Jordan says.

Copyright Blue Ox. Do not reproduce without permission.

Copyright Blue Ox. Do not reproduce without permission.

Here’s another of his favorites. Although the Jazz Greats may seem a little obvious, the Arthur Dent (Hitchhikers’s Guide to the Galaxy) and cat’s lives twists add a lovely resonance to the puzzle.

Copyright Blue Ox. Do not reproduce without permission.

Copyright Blue Ox. Do not reproduce without permission.

(There are just seven hills of Rome if you were wondering.)

From a programming point of view, there’s almost nothing in Red Herring that a competent coder couldn’t put out with a few weeks of effort and testing. The secret to its success isn’t its GUI or its graphics. Like the best of games, it’s a gateway to a larger experience. The solid puzzles behind the game are the basis of that experience.

Between its respectful balance of free-and-paid elements, and its commitment to ensuring high-quality puzzles, Blue Ox has evolved from a one-man effort to nearly a dozen employees servicing a core family of applications. If you’re starting your own games business, there are a lot worse business models you could follow and few that get it right more than this.

When your client demands Swift

Every day, more and more developers are being hired based on their Swift skills. Apple is committed to Swift and Swift is the future. Not a day goes by without some developer wandering by for Swift peer support with “I have to use Swift” because it’s in the contract.

I have shipped only one Swift app for live app store sale and I absolutely love Swift. Everything else remains in Objective-C.  And, yes, it’s painful to move back and forth between languages. As my brain trains for Swift, my Objective-C reflexes are taking a big hit.

Swift, despite migration support and ever increasing stability of language fundamentals, is not stable or will be for a while to come. So how do you break the news to your client, your boss, or that new guy on your team who saw a few WWDC videos that Swift is better suited for a long-term investment than short-term development tasks?

From a smart manager’s point of view, existing code bases, a known stable development path, and a pool of trained developers is more valuable than a scary new language still in development. The lower the risk of failure the better: deadlines are everything when it comes to bonuses, promotions, and job stability. When you have a stable Objective-C code base, why risk your credibility, your job, and your career for an unstable language and API? Experienced managers are the easy sell.

But more and more, people are coming to me and saying, “It’s next to impossible to explain this and sell Objective-C inside any large group or corporation. They look at you as if you’re crazy. Apple says Swift is now. They don’t get the push back.” Apple’s message of “Swift now. Swift for production” is becoming a big issue for developers.

Unless you can express a strong message of investment, stability, risk, and reward you’re going to be in trouble. I’m not saying “Don’t develop in Swift.” For many developers, the language benefits outweigh the refactoring costs that will be incurred over the next few years. It’s the people who don’t see the full picture and timeline that are and will be struggling, the ones jumping in without properly seeing warning signs.

It takes a good six months or so to retrain your brain into Swift development patterns. It will take several more years for the language to stabilize. When you think “Swift”, you shouldn’t be thinking quick-hit-then-walk-away projects. A Swift project means a long term commitment, unless you never plan to re-use any source code, fix any bugs, or provide any upgrades to your apps.

This isn’t the first time the industry has met this issue: think about how C# developed over its first decade. I’m told that many programmers found little projects, worked through them, and gradually built libraries and codebases to minimize maintenance costs over time. Now, as then, training and acquiring developers in anticipation of language stability is and was a challenge.

It comes down to this. If someone is pushing hard for Swift for full apps or critical production code, make sure they know the commitment they’re buying into with associated migration and core refactoring costs, such. Otherwise, Objective-C is still, and will continue, delivering product.

Thanks Mike Prenez-Isbell, Director of Mobile for Univision Television, and the other unnamed developers who spent time chatting with me about this topic.

Swift bracing

By convention, Swift embraces the “One Truce Brace Style” or 1TBS as its standard for laying out code. A variation of K&R bracing, 1TBS adopts the following features:

  • Opening braces appear at the end of the statement that establishes a clause
  • Else statements appear between paired close and open braces
  • All clauses are braced. Single-line clauses use mandatory bracing, just like multi-line clauses. Bracing ensures that all code line insertions will be safely added, and cannot break the intended flow.

A typical Swift if-statement looks like this, incorporating the 1TBS features listed above.

if let value = key {
   // ...do something
} else {
   // ...do something else
}

Xcode automatically styles code using 1TBS and Apple’s sample code and standard library use it as well. Despite this, you can easily override Xcode to incorporate Allman style, also known as “BSD style”.

Unlike 1TBS, Swift Allman wraps its opening brace so there’s always a clear visual path between opening and closing braces. Here is the Allman adaptation of the if-statement you saw previously.

if let value = key
{
   // ...do something
}
else
{
   // ...do something else
}

You can easily trace each opening brace to its closing partner and the else statement sits on its own line.

I mention Allman because Swift is not a language demanding vertical compactness. Clarity and safety should always win over succinct form.  Apple writes,

Clarity is more important than brevity. Although Swift code can be compact, it is a non-goal to enable the smallest possible code with the fewest characters. Brevity in Swift code, where it occurs, is a side-effect of the strong type system and features that naturally reduce boilerplate.

It’s a shame then that the language has adopted 1TBS over Allman when the latter exposes scope so beautifully and the former can be quite hard to follow, especially with respect to complex declarations that include external and internal labels, default values, and other complicating features:

Compare this example in 1TBS:

public extension Contextualizable {
    public func BuildContextError(
        items: Any...,
        file: String = (__FILE__ as NSString).lastPathComponent,
        function: String = __FUNCTION__,
        line: Int = __LINE__
        ) -> CoreError {
        
            let reasons = items.map({"\($0)"}).joinWithSeparator(", ")
            let context = "\(function):\(self.dynamicType):\(file):\(line) "
        
            return CoreError(reasons, context)
    }
}

with its Allman counterpart.

public extension Contextualizable 
{
    public func BuildContextError(
        items: Any...,
        file: String = (__FILE__ as NSString).lastPathComponent,
        function: String = __FUNCTION__,
        line: Int = __LINE__
        ) -> CoreError 
    {
        
        let reasons = items.map({"\($0)"}).joinWithSeparator(", ")
        let context = "\(function):\(self.dynamicType):\(file):\(line) "
        
        return CoreError(reasons, context)
    }
}

The Allman example simplifies the layout, making it far clearer where each declaration (Contextualizable, and BuildContextError) begin and end.

Swift’s worst bracing sin actually appears in switch statements (although get and set for properties are also not without sin). Left-aligned cases and defaults make its switches a horror to scan.

switch item {
case "B", "C", "D": print("Hello")
default: print("World")
}

Bracing also plays an in-line role due to Swift’s functional programming support. An in-line map can appear with or without parentheses (I use the Rule of Lily, which supports parens) and with or without in-brace padding.

This example skips that padding:

items
    .map({"\($0)"})
    .joinWithSeparator(", ")

This example uses padding:

items
    .map({ "\($0)" })
    .joinWithSeparator(", ")

I am currently leaning (slightly) towards the padding side of things although my personal style to date has not incorporated it. This example also uses indented dot-prefixed fluent chaining, although that’s probably a better subject for another post.

 

Marking symbols: Does Swift need more than _unpublished?

If you haven’t signed up for the many Swift mail lists, you may want to reconsider. Yes, your in-box will be completely bombed, and the signal to noise ratio is not ideal, but there are some really great discussions going on right now just after the open source launch.

One discussion that caught my eye today involved marking symbols as optionals. I’m not particularly enthused about this suggestion. The proposed idea is to introduce “greater readability” (the  marker would instantly identify a symbol as storing an optional value) and allow compiler checks for errors in use.

While I don’t think this would would be a valuable language change, it did get me thinking about symbol conventions. At this point, the only symbol convention I know of that is widely used both inside and outside Apple is the underscore prefix to mark unpublished/private symbols.

For example in the standard library, you find items like _SinkType.

public protocol _SinkType

The underscore prefix convention indicates symbols that aren’t meant for general consumption by third parties.

This got me wondering. Are there other common conventions you’re using in your Swift code to mark symbols? For example, I don’t see Hungarian notation being used widely, even for k-constant prefixes. (Maybe one or two has snuck into my code, but they didn’t stay. I think.)

Instead, I see Swift moving proactively to remove excess linguistic fluff. As part of the Swift programming language audits and evolution, Cocoa is adopting more Swifty™️ naming conventions and dropping many NS prefixes.

In such a philosophy, is there room for extra symbol lint? Or does the utility of symbol annotation outweigh cleaner looking but less intelligable code?

You tell me. Drop a note in the comments, tweet, or send an email. I’d really like to hear what conventions you’ve adopted and how they turned out!

Apple TV: Exploring physical activity

Incorporating, or more accurately trying to incorporate, physical activity into a tvOS app isn’t easy. Apple TV is no Kinect or Wii. At this time, about the best you can do with “native equipment” is wave a Siri remote around in the air or pop it into a pocket and use it as a kind of pedometer when walking on a treadmill or in place.

I spent a bit of time reviewing some of the “greatest hits” of physical TV gaming from walking companions to boxing/cheerleading games (would be much better with a secondary nunchuck) to yoga/balance and so forth. The best of these look at a lot more than a single arm-action point of control.

If you don’t mind going cross-system, of course, you can use motion features already on iOS and project them (directly over AirPlay or indirectly through Bonjour, etc) to a tvOS app but we’re already now talking bigger, bulkier, more planning, less impulse use, and less tvOS “app” design.

In theory you can use a wrist strap of some kind with the Siri remote and rely on arm motion to model physical activity. The chances of flinging the remote remain quite high unless the remote is physical tied down to a forearm, requiring a well-designed physical adaptor.

Conclusion? At this point, Apple is wasting a strong health branding component with its Apple TV product. Between the watch, iOS Motion, and Health Kit, Apple TV should be much more proactive than apps limited to logging meals (still easier to do on an iOS device) and offering coaching advice.

Opportunity wasted, premature entry onto the market, or simply wrong aim/branding?

tvOS: Designing for Groups and the Living Room

For the most part, and I don’t mean to be overly critical, there are better ways to pass your time than with most tvOS App Store offerings. This weekend, I decided to put together a small game. More specifically, I wanted to create a game that highlighted a few key design points.

Realities

When it comes to tvOS, you must accept a few basic realities:

  • Users sit relatively far away from the TV. It’s vital that you test your app from across the room and not just at your computer.
  • Users cannot touch the TV. Well they can but it isn’t part of your app interaction and it gets the TV dirty.
  • Users will at a minimum have a remote control on hand, probably a Siri remote. All apps must be written with that as a common denominator. Given Apple’s controller policies, I don’t really see hardcore gaming taking over the Apple TV platform any time soon. I made sure that my game worked with the old style Apple remote as well as the Siri remote.
  • Users may get up and go grab a soda or hit the bathroom at any time. It’s nice when the game waits for them to come back.
  • There may be several people in the room at the same time. An app shouldn’t be single-user centric. I see far more opportunities for integrating the platform into family and social situations, even for single-remote apps.

It’s these social situations in particular that got me thinking about living room play, and how some lessons of Wii Party/Mario party might transfer to tvOS. With multiple people present, you’re never going to fully immerse yourself in a game, but that’s not really a bad thing. I love apps that bring people together and enable them to interact both with the app as well as each other.

Slow Gaming

I decided that I wanted to write a slow game. I first heard about “writing slow” when doing background research for a write-up about A Dark Room. Although I don’t think tvOS is well suited for the kind of play-by-waiting game that A Dark Room represents, the notion of programming around time and its passage really grabbed me.

So I started thinking about what it took to slow down my trivia game to make it more suitable for playing in the living room with other people around, allowing time for talk and debate. I added a lot of “wait fluff”. To pick a category, you spin a wheel.

Screen Shot 2015-11-11 at 2.31.14 PM

Each question is delivered into place by a helper. Questions don’t just pop onto the screen:

Screen Shot 2015-11-11 at 2.31.24 PM

Questions slowly fade into view and when you answer, the answers fade to reveal your results. After that, the continue button takes a second or two to appear, letting you absorb before moving on.

Screen Shot 2015-11-11 at 2.31.29 PM

Designing for Discussion

As a big motivation, I didn’t want this to be a single player game. When testing it with my kiddos, I observed their “skinner box” impulses of “answer/reward/answer/reward” and designed against it.

As I introduced each pacing change, the game itself changed for us. It was still a bunch of trivia questions but now we started talking about the possible answers, which ones we thought were right, and weighing our choices because we were no longer under any pressure.

I also opted to eliminate all scoring and “rounds”. Nothing ties you into to this app. You can hop in, play some questions, and hop right back out. It’s stateless: much more like a deck of trivia cards like the ones you might carry along for a car trip than most of the other offerings on the app store.

That casual in-and-out makes it a lot easier with social situations. “Wanna play a few rounds of trivia” creates a much lower entry point than “Let’s play a fully structured game”. In this, the game serves the people playing it, and not the other way around.

Simplified Interaction

Unlike touch-based apps, I wanted Triviata input to be as simple as possible. I was in a mindset of “be the remote, respect the remote, limit the remote.” In fact, I reduced the entire interaction language to clicks. There’s a lot of clicking in this app.

Screen Shot 2015-11-11 at 2.30.57 PM

Of the six buttons in my app, two of them are automatically selected for you. They never feel like “real” buttons, such as the “Click to Play” on this screenshot, which uses a custom button style to avoid highlighting.

The other four buttons (the answer buttons) use strict up-and-down selection. I could have built much more complex gestures but I needed interaction to be brainless and intuitive. I wanted to deliver lightweight access to the questions and answers.

I ended up chopping out a lot of code that didn’t make the final cut. I’ve got some nice work done on other interaction styles that I may end up using elsewhere (for example, rotating the controller to pick from a dial — this can also be used to “drive” the remote when held sideways as a steering wheel). I’m not at all upset that I ditched everything. I think there’s a lot to be said for simple.

Whitespace

I also went simple, simple, simple with each screen. Lots of whitespace, few on-screen elements. As a point of comparison, consider this screenshot from a competing app. This is a ready-for-gameplay presentation.

Screen Shot 2015-11-11 at 2.07.03 PM

Imagine trying to read that from a normal couch distance. I’ll give credit for their Jeopardy set-up for structured gameplay but even this felt way too busy:

Screen Shot 2015-11-11 at 2.43.12 PM

I like the design on this one a lot more but again, think about those small text features when placed across a room:

Screen Shot 2015-11-11 at 2.39.56 PM

This next app opted out of multiple choice. You have to “think” or shout your answer before it’s revealed. That’s actually an intriguing way to involve group dynamics…

Screen Shot 2015-11-11 at 2.41.42 PM

Of the apps that aren’t actually my app, this is probably my favorite presentation. They went with timed questions. I went more zen. I do however like the clean setup and the gray “whitespace”.

Screen Shot 2015-11-11 at 2.44.55 PM

Wrap-Up

In the end, I expect to sell all of about 6 or 7 copies of my app. (Thanks for the coffee money!) It really was more an exploration of design and interaction principles than full-blooded app development, even if I think the end-product is fun to play.

If enough people buy the app, though, I promise to use some of the money to buy better trivia packs. I used public domain ones and some of these questions date back to the neolithic periods and not in a good way.

Got feedback about my app in particular or tvOS design in general? Let me know.

tvOS and iOS: Some thoughts

Two questions to start with. And I promise you they’re not trick questions.

  1. What is the greatest commonality between tvOS and iOS?
  2. What is the greatest difference?

p.s. There is a second page of this post. Bonus points if you can find it.

More thoughts on tvOS development

The more time I spend in tvOS and on Apple TV, the more I find that it’s an environment better suited for the “big guy” crowd than independent developers. Its app store is hard for anyone who isn’t a preferred partner and the price points Apple’s partners have launched with won’t sustain a much reduced customer base for anyone who isn’t big to begin with.

I see ATV doing best for successful brands and products who want to extend from iOS rather than introduce new tvOS-specific products. In such cases, ATV offers Apple-watch-like extension of functionality instead of a standalone system.

You can advertise the features directly within an app, and offer tvOS support for free or low costs without compromising your bottom line. The real money remains on iOS and tvOS apps add value. This helps skip any issues of app store discovery.

You cannot compete with built-in content like weather, traffic, schedules, reminders, media access, and so forth. And the tvOS SDK doesn’t offer lightweight glances and complications that would be the best way to supplement media consumption.

When it comes to games, ATV is suffering in several ways. First, it doesn’t offer an Apple branded game controller — it’s all third party. The Siri remote kind of sucks when it comes to interactions, although I have created some Wii-like proofs of concepts for using the remote sideways as a steering wheel.

Real gaming needs more than an accelerometer and the Siri remote doesn’t have the buttons or hand-feel that would win. That means purchasing real controllers and building games that properly leverage those controllers. Those are two serious barriers to surmount. (Plus I should note that games must work with just the Siri remote, according to current Apple guidelines and cannot depend on controller purchases.)

Unfortunately, ATV also has a mission issue. It’s a media center that can also play games. It doesn’t have a big game selling point, whether physical movement like Kinect or Wii or “best games available exclusively” like other consoles.

That said, Apple’s sweet spot has always been health (from jogging with your iPod to HealthKit and ResearchKit). It would be great to see Apple introduce some kind of physical interaction features (like a wii fit board, or whatever) that could build on this “Get Moving” brand and get kids up and off the couch for more physical gaming.

Right now, if kids want to vegetate, they can already do that with their iPads and  in any room of their house and in a car. The iPad’s touch screen offers a lot more potential than the TV’s “kind-of-point-at-stuff” interaction. I also think most learning titles are still better on the iPad and with touch interfaces. Think Khan Academy type stuff.

The big question for current ATV apps outside of controller-based-games is “can this kind of be a TV channel?” and if the answer is anything other than a clear “yes”, then tvOS is probably not the right platform.

For example, think of a “Home Control” channel, where you tie into security cameras, garage door states, and thermostats. It’s a great way to integrate existing Apple frameworks with tvOS opportunities.

Life coaching products in particular would also benefit from tvOS check-in and review. It’s a natural fit to extending app flow into the living room. While traditional games have received the most press, I see a real target of opportunity here for display on a screen that’s likely quite close to the kitchen (calorie tracking) and your track sneakers (exercise tracking).

Right now tvOS and ATV feel like they haven’t entirely been realized: as if they’re still more hobbies than products. There’s a lot in these new products to like but I think Apple has to think through this push into applications to better define the niche or niches it intends to fill.

What makes good code

Got an email recently asking: “What makes good code?” I was a bit sick at the time, so I rambled the following off the top of my head as quickly as I could before taking some Advil, decongestants, and expectorants and then lying back down. Now, in somewhat better health, I thought I’d share these thoughts because I feel they’re an interesting starting point for an important discussion. At the time, I wrote:

It’s probably easier to ramble by phone because I’m currently under the weather but off the top of my head, here you go:

  • Good software code doesn’t just compile, it communicates. It talks to you as a developer here and now and to future you, who will be maintaining this code. It is comprehensible to your team and to anyone who will look at it externally.
  • It always chooses reliable and testable over clever, and prefers to take an extra step or ten if needed to make its intent and outcome clear.
  • It’s code that thinks about scale, about living in a forest as well as being a single tree, and being run a million times at once as well as once.
  • It’s code that believes in being broken down into sensible units instead of massive single implementations.
  • It’s code that understands that it will be implemented not once or twice but reviewed and refactored to be the best and most robust implementation possible.
  • It’s code that thinks globally and provides hooks for many cultures and multi-abled users, which is a real code-level thing — how you add internationalization and accessibility and not as an afterthought.
  • It’s code that thinks about not just the specifics of the destinations it will run on today but how to adapt for when those destinations change over time. 

That all said, what are your feelings on what makes good code and what would you add to, remove from, or modify in my initial list? I’m looking forward to hearing what you have to say.

Update:

Seivan Heidari suggests: It’s code that exposes externally-consumed APIs without sharing internal implementation details.

Anonymous suggests: It’s code that ships. Good code works, does what I need, is delivered on time, and the rest of these points be damned.

Dave DeLong: Great code leaves you in awe and inspired to go write your own great code.

Paul Cantrell: It’s code that strikes a mindful balance in all the tradeoffs these other bullet points imply. It sees engineering tradeoffs, not dogmatic absolutes. It doesn’t let tools or techniques become in-group status markers.

Rainer Brockerhoff: It’s code that I can easily reuse (often years later) and which can be extended/adapted in a few lines.