1. This Week I Learned #17

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • The coastline paradox refers to the phenomenon where the fractal nature of coastlines causes their length estimates to vary widely depending on the scale of the ruler used. This length tends towards infinity as the measurement unit gets smaller and smaller, going against the logical expectation when measuring a finite distance (via Marc Edwards).
    • The proportionality bias refers to our tendency to assume that major events have major causes. While it’s often cited as a likely reason people believe in conspiracy theories, it’s also why programmers spend hours debugging a problem, probing every nook and cranny, only to find out that the cause is much more trivial than what was anticipated.

    # Design

    • In 3D graphics software, namely Blender, a shadow catcher is a completely transparent material that “catches” and renders the shadows of other objects in the scene—useful when exporting 3D renders for further 2D composition and editing. When using the Cycles renderer in Blender, this is as easy as ticking a checkbox. In EEVEE, Blender 2.8’s new rendering engine, it requires using a custom shader to obtain a similar effect.

    # Programming

    • I went trough the first half of the Tour of Rust guide with the intention of getting more familiar with its syntax and memory management APIs. Beside the relationship between ownership and mutability, many of the concepts introduced in what I’ve seen so far felt quite similar to their Swift counterparts.
  2. I enjoyed Chris Krycho’s take on the idea, but I totally understand where he is coming from. Like any other commitment, it takes time and energy that might not always be readily available.

    After four months of running this experiment, I am starting to feel the pressure. Some weeks go by where I don’t learn much worth mentioning, or simply don’t have enough time to elaborate. But I remain convinced this is a habit I’d like to keep—if anything, it helps me rebuild confidence in my ability to follow through commitments of this kind.

  3. This Week I Learned #16

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • This week I picked up aws-sdk-swift with the goal of integrating with SES, Amazon’s cloud email service. After some initial struggle figuring out which API version to use and how, I managed to send emails from a server-side Swift app I am currently working on.
    • Some valuable lessons about S3, AWS billing, and CDNs by Chris Short (link).
    • SwiftUI’s new Menu component is now available on iOS 14 as of Beta 3. I suspect contextual menus to gain more traction on iOS and I am happy to see them join a growing list of SwiftUI components.
  4. This Week I Learned #15

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • Understanding any topic in greater depth requires honesty, integrity, and patience. Thinking hard about the problem space and seeking first-hand experience also yields far deeper understanding than contenting oneself with the syntheses of others (link).
    • Beta invites to OpenAI’s API, powered by the new GPT-3 (paper), are starting to go out and some of the demos are generating a lot of buzz at the moment. This was the article that brought my attention to this.

    # Programming

    • How to properly use services in Vapor 4. I am still not fond of the amount of work involved, but it’s an effective way to extend the built-in capabilities of the default types.
    • How to use HTMLElement to build a custom DOM element that encapsulates structure, styling, and interactions (link).
    • How the isSource and properties arguments in SwiftUI’s matchedGeometryEffect work (link).
  5. On flatMapThrowing in SwiftNIO

    Johannes Weiss answering the question why flatMapThrowing (docs) is not a throwing flatMap:

    Functions that have this prototype: f() throws -> EventLoopFuture<Void> are in my view a bit user hostile. They can fail in two different ways: by throwing [and] by returning a failed future. That means a user needs to look for errors in two different places. […] On top of that: If an asynchronous function throws synchronously, is it really asynchronous?

    This one caught me off-guard more than once. Considering the signatures of map and flatmap (abridged for brevity):

    func map<NewValue>(callback: @escaping (Value) -> NewValue) -> EventLoopFuture<NewValue>
    func flatMap<NewValue>(callback: @escaping (Value) -> EventLoopFuture<NewValue>) -> EventLoopFuture<NewValue>

    It’s easy to assume that flatMapThrowing is a version of flatMap that takes a throwing closure of type (Value) throws -> EventLoopFuture<NewValue>. But that’s not the case.

    func flatMapThrowing<NewValue>(callback: @escaping (Value) throws -> NewValue) -> EventLoopFuture<NewValue>

    As for the name of the method, Johanness explains:

    Lots of people get confused by this, if I could choose again, I’d probably go for something like combineThrowing or so?

  6. How come “a11y”, the widely used numeronym of the word accessibility, is itself not accessible?

    Saving key strokes at the expense of readability is the antithesis of what accessibility stands for, in my opinion.

  7. This Week I Learned #14

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • Lambertian surfaces and their photometric properties, through this stunning interactive guide by Bartosz Ciechanowski.1
    • I learnt quite a bit from this exploratory piece by Mattt about how core concepts from the Semantic Web can be used to make the code we write semantically richer, unlocking new authoring, distribution, and reuse possibilities in the process.

    # Programming

    • How the new matchGeometryEffect works in SwiftUI. This new API enables synchronizing view animations and transitions regardless of their place in the hierarchy. It’s quite powerful and will make some previously labor-intensive effects much easier to achieve (link 1, link 2).

    1. If you had asked me ten years ago about how Wikipedia or Wolfram Alpha would look in 2020, I’d have pictured something along the lines of Bartosz’s work. Yet, we’re absolutely nowhere near that. One can’t help but wonder if we have been focusing on the right things all these years.

  8. On Static Site Generators

    Peter Zignego writes about his experience with Swift static site generators:

    After a bit of spelunking, I realized that it had been built with some beta version of Xcode long since lost to the sands of time — I was stuck with a binary I couldn’t run.

    Luckily most of this is behind us now. Prior to 4.0, this was a major drawback of using the language for general purpose programming.

    Over the course of the week I spent converting this site to use Publish, I was frustrated by a lot of the built-in assumptions and general inflexibility. While I am sure that it is a great Swift by Sundell generator, it is not (yet) a great general-purpose static site generator.

    As a Website maintainer, finding a static site generator that works exactly the way you want is no small feat. I used a handful in the past 10 years, across personal and client projects, and I still haven’t found the one. Plugins and extensions do help, but there will always be a set of assumptions that are not true for every project.

    But the beauty of open source is exactly that, so I forked it and fixed my two biggest issues.

    If you’re going to use a static site generator, use one written in a language you are comfortable with. Sooner or later, you’ll find yourself in a position where you need to patch the build system to add new functionality or modify existing one, especially if you are making Websites for a living.

    In practice I found [using an HTML DSL] to be more clunky and mistake-prone than just writing HTML with Mustache templates, which is what I was converting from.

    Couldn’t agree more as someone who always preferred templating languages (Mustache, Liquid, etc) to DSLs. The latter often introduce friction that seems unnecessary if you are already comfortable with HTML and CSS.

    I‘m not head over heels in love with Gatsby, but it’s versatile and battle-tested. I‘ll eventually look into migrating to a Swift build system, but I can’t afford the time to do so for the time being.

  9. This Week I Learned #13

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • I am a bit late to the r/covidcookery party, but this weekend I baked my first cake ever! An okay-looking, totally edible pound cake. There’s definitely a lot of room for improvement, but the sense of achievement when I took it out of the oven and it wasn’t a complete mess is quite the feeling. Thanks Alaa for the hands-on tips!
    • It took quaternions 150 years after their discovery by Williams Rowan Hamilton to find practical uses such as 3D computer graphics and robotics. Immediate applicability is never the primary goal of mathematical research (article via Hacker News).
    • Gemini is a budding client-server protocol aiming to offer a bloat-free alternative to the HTTP Web. It uses a Markdown-inspired document format and completely forgoes client-side scripting and styling (source).
    • I saw a PC ad on Japanese TV that ended with the Intel Inside slogan:「インテル入ってる」(interu-haitteru). Pretty clever for a marketing localization, right? Well, as it turns out, the perfectly-rhyming Japanese slogan came first (!) and served as inspiration for the English version, according to Susumu Furukawa, the president of Microsoft Japan between 1986 and 1992 (source).

    # Programming

    • I totally missed this initially, but it’s possible starting iOS 14 to customize the navigation bar title in SwiftUI (link).
  10. Mattt on WWDC 2020

    It’s refreshing to see Mattt’s reasoned take amidst all the attention-seeking headlines this week:

    As it turns out, going fully remote wasn’t merely good enough — it was, in many ways, superior to the original thing. […] Sessions are tight and well-paced. Rather than stretching or cramming content into a fixed time slot, they’re as long as they need to be.

    This definitely echoes my impressions. As someone who mostly followed along from home in the past, not only did I not miss much this year, but I got treated to a much improved remote experience.

    Mattt also brings up the topic of Excitement—or hype, as I often call it—and productivity:

    Here’s the thing about excitement: It’s kryptonite to developers. Excitement messes with our ability to focus on one thing, which is already a big struggle for a lot of us (myself included). When you’re excited, it’s almost impossible to get anything done.

    This is true for any endeavor, but especially so for software development.

    There are plenty of voices in the community who are echoing this excitement. I can’t add anything to that discussion. And besides, that’s not really where my head’s at right now.

    The official Apple content generates enough sense of FOMO as it is. Combining that with a firehose of What’s new in X blog posts, podcasts, YouTube videos, and tweets doesn’t help much as far as I am concerned.1

    It’s been an exciting week, so take a moment to collect yourself. Go on a walk. Take a hike. (Be safe about it.) Do whatever you need to break free of the “reality distortion field”. Once you do, you’ll have the necessary distance to determine what new technologies you should pay attention to and what you can ignore for now.

    Solid advice, WWDC or otherwise.

    1. I published my personal notes throughout the week, but my audience is infinitesimally tiny. Not to mention that I usually publish these things primarily for my future self.

  11. WWDC 2020: Day 4-5 Takes

    WWDC 2020 is officially over. Here are some notes based on a handful of sessions I watched in the past couple of days.

    • I am quite happy with all the WKWebView improvements that made it in this release. In particular, callAsyncJavascript will make bridging async JS and Swift a less painful affair. That said, some of these APIs, including the aforementioned, seem to be missing from the first beta.
    • Core Data didn’t get the overhaul many of us were hoping for, but it gained some useful APIs to help with batch operations. I’ll take that.
    • I am happy that we got a couple of sessions about unsafe Swift, an area that’s becoming increasingly important for those of us using Swift for server-side development (C library wrappers, database drivers, etc).
    • Speaking of server-side, it’s refreshing to see a session about using Swift on AWS Lambda. Apple has a lot of leverage when it comes to adopting Swift on the server, and sessions like these are a good sign that they are invested, at least to a certain degree, in promoting that.
  12. WWDC 2020: Day 2-3 Takes

    I’ve managed to watch most of the sessions released today and yesterday. Here are some of my personal highlights:

    • WebExtensions API support in Safari is excellent news for people building browser extensions. For those not familiar, it’s a standard way of developing cross-browser extensions, currently supported by both Mozilla and Google.
    • On the subject of Safari, several features and improvements made their way in this release. I’m particularly excited about the CSS bits, such as support for the :is() pseudo-selector, system font families, and CSS Shadow Parts—a way to allow Web Components to expose internal elements to the outside for styling purposes. Oh and WebP support.
    • As part of the Web Authentication API implementation in Safari, you can now use Face ID and Touch ID for user sign-in on your Web apps. You heard that right.
    • The new SwiftUI app life cycle is nothing short of impressive. I have been upgrading all my unreleased apps to this new API—since it’s iOS 14 only—and it’s been eye-opening to see how far this declarative approach goes in getting rid of boilerplate.
    • Contextual menus are now generalized in iOS and can be invoked from any button without requiring a long press or adding an overlay on top of the view. This is my favorite new addition to iOS this year—by far. Action sheets were always clunky to work with, and popovers felt off on the iPhone. It’s worth noting that SwiftUI doesn’t seem to have access to this new API as of this beta (Feedback: FB7776866).
  13. WWDC 2020: Day 1 Takes

    Instead of doing live reactions this year, I opted to jot down some notes during the Keynote and the State of the Union and share them in one go. So here goes nothing!

    • The home screen and springboard changes in iOS 14—App Library and Widgets—are clearly going towards adjusting the cognitive load in order to better surface the information that matters to the user at any given time. Let’s be honest, the icon grid has reached its peak usability almost a decade ago.
    • Another area that got a lot of attention in iOS 14 are the different interruptive modes in the user interface. In iOS 13 and earlier, receiving a phone call or activating Siri takes over the entire screen, making them effectively separate modes that interrupt the user flow. Starting iOS 14, these are replaced with lightweight overlays that preserve the current context.
    • App Clips are yet another aspect of evolving the app paradigm to better fit real world usage scenarios—the other two that come to mind are widgets and extensions.
    • The context preservation theme is salient in this year’s iPadOS update; not surprising given that context might be even more important on a large screen where multiple things could be happening at the same time.
    • The introduction of sidebars for in-app navigation in iPadOS 14 is another net win on the information density front. Sadly, App Library and inline widgets seem to be missing from the first beta.
    • I am very happy to see that pencil handwriting recognition works across the OS, supports Chinese characters (Kanji), and detects different languages in the same sentence. Alongside built-in translation, these are powerful new additions for language enthusiasts like myself. Update: It seems like Japanese is not supported in Beta 1. Bummer.
    • The reason Apple didn’t spend time talking about the ability to change the default browser and email client on iOS 14 is simple: most consumers couldn’t care less. If anything, antitrust regulators might be more into this one.
    • Built-in tracking control in Safari is looking to be intuitive and will likely make the current crop of content blockers obsolete; nothing beats what’s already there by default.
    • The macOS 11 Big Sur redesign is substantial. I have mixed feelings about different aspects, but I will leave that for later.
    • Control Center and the new Notification Center on Big Sur are welcome imports from iOS. The open nature of the Mac always allowed power users to devise ways to surface the information that matters to them (such as menubar apps), but for the majority of users, this is an accessibility upgrade.
    • The transition to ARM is going to be the first major architectural transition that I witness as an Apple platform developer. My main takeaway is that the timeline seems to be much more aggressive than anticipated.
  14. This Week I Learned #11

    Here are some of the things I learned this week, when I wasn’t biking or basking in the sun.

    • Why books—and other traditional methods of knowledge transmission—don’t always work (link)1. It is no coincidence that this essay resonated with me a great deal—learning is a topic that’s very near and dear to my heart. Most of the skills I use today to do my job are self-taught, and learning languages was and is still a big passion of mine. Andy expands on the idea that without additional metacognitive skills, reading books is insufficient to acquire knowledge and understanding due to the flawed transmissionist model that they are implicitly based on.2
    • Speaking of reading, I picked up the latest work of Shūzō Oshimi, わだち (chi-no-wadachi, Trail of Blood, 2017–ongoing), and I wasn’t disappointed. What starts out as a run-of-the-mill slice of life quickly spirals into an unsettling psychological thriller with some of the most nail-biting moments I’ve experienced in the format. If this sounds like something you would enjoy, give it a shot (日本語, English).

    1. I’ve had the pleasure to interact with Andy Matuschak, the author of this essay, when he used to work on UIKit at Apple. He was kind, helpful, and profusely generous with insider knowledge that helped me improve some of the articles I wrote on thoughtbot’s blog. I stumbled across his website this week and I am really looking forward to more of his work in the field of learning and cognition.

    2. As a matter of fact, “This Week I Learned” is a metacognitive tool I concocted to help me remember the new concepts, ideas, and techniques that I learn during a given week.

  15. Shipping a macOS or iOS app nowadays without a setting to match the system appearance is an increasingly harmful accessibility oversight. Discord on macOS is one of the offenders that has been consistently annoying me since earlier this summer.

    Discord appearance settings

  16. Nikita Prokopov on Syncthing

    Nikita Prokopov sharing his experience using a free and open-source alternative to Dropbox called Syncthing.

    Syncthing is everything I used to love about computers. It’s amazing how great computer products can be when they don’t need to deal with corporate bullshit, don’t have to promote a brand or to sell its users. Frankly, I almost ceased to believe it’s still possible. But it is.

    It is indeed heartwarming to see products like these still exist.1 I gave up on Dropbox long ago, and I have the same iCloud issues Nikita outlined. I am very happy to jump ship after reading this glowing review.

    1. Bonus points for being made in Sweden under a non-profit!

  17. This Week I Learned #10

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • Spontaneous cognition and how random thoughts emerge from the brain (link).
    • IPFS, a peer-to-peer protocol powering a number of decentralized Internet projects. I knew about Solid and Dat, but never heard about this one, which seems to be even more popular within the decentralized Web community according to this survey.
    • NGINX has now a preview release with HTTP/3 over QUIC support. The announcement blog post has a good overview of the technology and how it’s different from its predecessors.

    # Programming

    • The Fail publisher in Swift Combine. Similar to its sibling Just, it competes immediately, but with a failure instead of a value—useful for testing and debugging the unhappy paths in your app (link).
    • Writing tests is vital for maintaining a healthy, and functional, codebase. This is less of a revelation and more of a reminder: a test I wrote while debugging a database query issue helped me discover and fix two unrelated bugs.
  18. This Week I Learned #9

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • The current chain of events unfolding across the US made me realize how much work still needs to be done in a country that prides itself on equality and justice. #BLM
    • Tools for better thinking (link). A nifty website with an assortment of techniques and frameworks to help with decision making and problem solving. The Dropbox Design blog has more on some of these models.
    • Circle packing (Wikipedia). I was introduced to the concept of packing density in business school as part of a product design and packaging workshop, but I never had the chance to take a look at the math behind it. Geometry is beautiful.

    # Programming

    • The UI on the Crew Dragon was built using Web technology running on Chromium, according to this AMA.
    • I’ve used Swift key paths here and there, but I never explored the lesser known parts of this API. This week I picked up AnyKeyPath and PartialKeyPath<Root> and used them for a server-side project I am working on (link).
    • Android phones seem to be crashing when using a particular image as a wallpaper (link). According to this Twitter thread, the issue happens during color space conversion, where the formula used to create a pixel lightness matrix rounds the color values up, resulting in a RGB sum greater than 255.1 This in turn causes an out-of-bounds exception that keeps happening every time the system UI process restarts.

    1. This formula is formally called sRGB Luma (Rec. 709). I’ve written more about it and other color lightness topics here.

  19. This Week I Learned #8

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • The difference between input and output randomness in game design (video). The gist of it that randomness that occurs before a player action is referred to as input randomness—a prominent example being procedural level generation—while randomness that occurs after user action is called output randomness, such as the case with loot boxes and success rates.

    # Programming

    • I’ve been using Markdown for years, but I never realized you could add image titles like this: ![Alt](/url/to/image.jpg "A title"). Granted, I usually avoid using the title attribute for the reasons outlined here.
    • Core Data became a lot easier to work with since the last time I used it, which was before NSPersistentContainer for those familiar with the framework.1

    1. It still feels clunky by today standards—can we have the Codable of data persistence already?

  20. A SwiftUI function grapher in 160 LOC. The framework might be immature, but it made a lot of my work a tad easier. I will share the source as part of a project I am currently working on, so stay tuned!

    A function grapher in SwiftUI

  21. This Week I Learned #7

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • Concern trolls. I had never heard this expression before until I read about it in the context of US politics. It refers to a person who, in order to be accepted, pretends to agree with a group of people about a given topic, only to constantly seek to sow doubt and confusion among their ranks, disguising their ruse as “concerns”.

    # Programming

    • If there is something that can be exploited, you can rest assured that unscrupulous Web sites will exploit it. The latest episode is port scanning through WebSockets. I didn’t even know this was possible, and I am kind of bummed that browsers keep encroaching more and more on operating system territory. I mean, who in their right mind wants a random Web site to control their device vibration?
    • Boolean blindness and why booleans are not always the right choice in the context of data modeling. Via Matt Diephouse’s “You Might Not Want a Boolean”.
  22. I find it extremely frustrating to get a YouTube video as an answer to a programming question. I watch videos when I want to leisurely learn about something new, but when I have a specific problem to solve, they are my very last resort.

  23. A Stable Modular ABI for Rust

    Before Swift Evolution, I had no idea what an ABI was. Today, even though I still get lost when it comes to the minutiae, I can at least follow along threads like this one without feeling too uncomfortable.

    It’s also eye-opening to see how different communities and companies prioritize different aspects of a programming language. Rust got async/await since version 1.39.0, released last November, but they have yet to stabilize the ABI. Apple went about it the other way around with Swift, given the importance of ABI stability for their platforms.

    A stable ABI would allow Rust libraries to be loaded by other languages (such as Swift), and would allow Rust to interop with libraries defined in other programming languages. […] However, a stable ABI is not all peaches and roses. Having to standardize the memory layout of data can limit the number of optimizations the compiler can perform.

    A modularized ABI would be optional while compiling. This modular ABI could be published as a versioned crate. If the ABI ever needs a backward-compatibility breaking change, the change could be made within Semver. Alternatively, a new ABI-compliant compiler backend could be developed, or the current compiler backend could be extended to support an ABI feature flag that would toggle ABI compliant builds.

  24. This Week I Learned #6

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • How the MissingNo. sprite is rendered in Pokémon. If you are into retro games and programming, I highly recommend this channel.
    • The Scunthorpe problem is, according to Wikipedia, “the unintentional blocking of websites, e-mails, forum posts or search results by a spam filter or search engine because their text contains a string of letters that appear to have an obscene or otherwise unacceptable meaning.” Via Scunthorpe Sans.
    • How HTTP/3 and QUIC work. I hadn’t heard about QUIC until earlier this week and watching this talk by Daniel Stenberg was a perfect way to catch up. Thanks Alaa for the tip!

    # Programming

    • Global variables in Swift are lazy—it’s in the docs even. I don’t know how I ended up with the assumption that they are eagerly evaluated (thanks again, Kim!).
  25. As days keep getting longer here in Stockholm, I’ve been relying on the light appearance of macOS to avoid straining my eyes. One thing that caught me off guard is the dearth of decent-looking light themes for text-based applications. It’s almost as if developers have an overwhelming penchant for dark interfaces…

  26. This Week I Learned #5

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • 自粛じしゅくつか (jishuku-tsukare). An expression that’s gaining momentum right now in Japanese media, meaning getting tired of voluntary confinement.

    # Programming

    • Visual explanations go a long way in demystifying tricky topics such as floating numbers and regular expressions.
    • JavaScript frameworks are costly, argues this well-researched piece by Tim Kadlec. One would think that performance tends to get better over time in technology, but that doesn’t seem to be the case in JS-land.
    • I picked up some LaTeX this week for writing mathematical notations and this cheatsheet came in quite handy.
  27. This Week I Learned #4

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • The Blub Paradox (thanks Kim!). Coined by Paul Graham in his 2001 essay “Beating The Averages”, this concept refers to the inability of a programmer using a hypothetical mid-level language, called Blub, to:

      • Use a lower-level language due to lack of features they are familiar with in Blub.
      • Realize that they are looking at a higher-level language when they evaluate one.

      I have some reservations about this one, based on my own experience, but it’s a nice tidbit nonetheless.

    • I did some reading on flying machines this week and picked up a new word: ornithopter.
    • I almost feel ashamed for not knowing this one until this week1: deuteragonist and tritagonist.
    • This answer by Dave Abrahams to a Quora question about the most important things involved in delivering a great software library. If I had to pick only one, that would be “rigorously document“.
    • The .org TLD is saved!

    1. Not gonna lie, it’s a fairly prevalent feeling throughout these updates.

  28. This month I noticed a sudden influx of visitors to the We Need Chrome No More piece form last year—46k page views is way, way above the monthly average hovering around 1k. My self-hosted instance of Fathom shows some limited data about top referrers, but none of the numbers make sense, and I am totally fine with that.

    Website visitors, April 2020.

  29. Solutions, Problems, and Learning

    From a content creator perspective, it’s relatively easy to write about solutions. Tips and tricks. How to do X or Y. Lessons learned. In contrast, it’s significantly harder to write about problems—what’s at stake and why it’s worth the effort. Understanding a given problem to a level where it can be distilled requires much more rigor and experience than presenting solutions to said problem.

    From a learner perspective, especially in their early stages of the learning process, it is far more worthwhile to understand the problems, challenges, and tradeoffs than to build a repertoire of solutions. Doing the latter without the former might work in the short and mid-term, but on the long run it is very likely to hinder personal and professional growth. Fast food is an apt analogy.

    While this dichotomy makes learning certain topics particularly hard, it’s not unsurmountable. One has just to look hard enough.

  30. This Week I Learned #3

    Here are some of the things I learned this week, in the order I’ve noted them down.

    • The words ”esoteric” and ”niche” do not have the same connotations. I used the two interchangeably in the past, and that resulted in some really awkward sentences. Thanks anonymous reader for the tip!

    # Programming

    • How the layout algorithm works in SwiftUI stack views. Huge props to Adrian Zubarev for making that task easier for me. I will be sharing more about these findings, and the context that motivated them, in the near future.
    • Database normalization and normal forms, through various articles and resources, including this one. I’ve intentionally tried to stay as far as possible from databases for the past 10 years, but now I feel like I am missing out on a fundamental aspect of building server-side software.
    • After all these years, CSS is still fun.
  31. I’m genuinely excited to see Chris Krycho adopt the format I’ve been recently experimenting with on this microblog. I’ve learnt a lot from reading Chris’ essays and journal entries1, and I am looking forward to reading more of these.

    1. That’s also where I got the assumed audience idea from.

  32. This Week I Learned #2

    Here are some of the things I learned this week, in the order I’ve noted them down. This week I created a separate section for programming to keep things tidy.

    • Contact tracing. A joint initiative by Apple and Google to help health organizations throughout the world slow down the spread of COVID-19. This excellent entry on NSHipster is a good place to start if you’re interested in the nitty-gritty details. The official documentation itself can be found here.
    • Last week I mentioned free access to the ACM Digital Library during COVID-19. This week I stumbled upon this list of similar offers compiled by Michael Tsai.

    # Programming

    • The relationship between size, stride, and alignment in the memory layout of Swift types, thanks to this excellent article by Greg Heo.
    • In Swift Combine, you can filter out nil values using .compactMap { $0 } (reference). I was using filter(_:) before but that still requires force-unwrapping the value in subsequent operations.
  33. This Week I Learned #1

    Here are some of the things I learned this week, in the order I’ve noted them down:

    • Calm technology. A term coined by PARC researcher Mark Weiser in 1995, referring to technology that does not seek to become the center of attention when we use it. It’s there when we need it, and out of sight when we don’t. More on the topic here.
    • Eggcorn. A phrase or expression that resulted from intentionally or accidentally substituting one or more words from an expression with similar-sounding words (Wikipedia). For example:

      • Praying mantis -> preying mantis.
      • Cut to the chase -> cut to the cheese.
      • Acorn -> eggcorn (duh).
    • The entire ACM Digital Library is free to access until June 30th. There’s more to COVID-19 quarantine than Netflix 😉.
  34. Dear GitHub,

    Where is my official dark mode support at? My eyes would profusely thank you for it. And they will be joined by many, many others in doing that.


  35. GIF Hunt?

    Product Hunt

    While browsing Product Hunt yesterday, I couldn’t help but get a strong mid-90s, GeoCities-esque, vibe as I scrolled past the animated GIF thumbnails.

    I get it. This is how the attention economy works, and the Internet loves them GIFs. But when everything is screaming for your attention at the same time, the whole thing becomes a kitschy, obnoxious mess.

  36. More on Metasyntactic Variables

    My good friend Mikael Muszynski sent me this nugget about metasyntactic variables:

    I was reminded of the fact that companies which speak primarily in Swedish have their own metasyntactic variables!

    The code will generally be written in English, but instead of foo and bar, they have a clever system:

    “Apa” is the word for monkey [in Swedish], and not only is it a somewhat amusing word, it also happens to start with the letter “a”!

    So the pattern goes apa, bepa, cepa, depa

    Clever indeed.

  37. Margin Considered Harmful

    Max Stoiber on using margins in UI components:

    Margin breaks component encapsulation. A well-built component should not affect anything outside itself.

    It’s very hard to disagree with this statement if you’ve been involved in any capacity with creating reusable UI components. Baked-in margins can and will hinder component reuse across different adaptive layouts.

    A few years back, margins were the only way to create float-based grid layouts in CSS. Today, margin gymnastics are no longer necessary.

    Instead of margin I have started using spacer components, which move the responsibility of managing space to the parent-level.

    Implementation details aside, delegating the spacing between adjacent items to the wrapping component is the right approach. For instance, SwiftUI uses a similar API to the one suggested in the blog post:

    VStack(spacing: 8) {
      Text(Item 1)
      Text(Item 2)
      Text(Item 3)
  38. Full-Page Screenshots in MacOS Safari without Extensions

    Here’s a new trick I picked up this morning: you can take full-page screenshots of any Web page in Safari for macOS without using third-party extensions.

    Before trying this at home, make sure you have the Develop menu enabled. In case it’s not visible in the menu bar, head to Safari ▶ Preferences ▶ Advanced ▶ Show Develop menu in menu bar.

    Once that’s taken care of, follow these steps:

    1. Head to Develop ▶ Show Web Inspector or use the Option + Command + I shortcut.
    2. In the first Elements tab, look for the html tag in the source tree.
    3. Right-click the html tag and choose Capture Screenshot.
    4. Choose a destination and save the file. Append the .png extension to the name if you want preview to properly recognize it as an image.

    Bonus: You can capture any HTML tag in the source tree, not just the root element.

  39. Metasyntactic Variables

    You know those placeholder words used when writing tests or documentation for software programs? They are called metasyntactic variables, and today I picked up some brand new ones beside the usual foo, bar, baz, and qux: corge, grault, garply, waldo, fred, plugh, xyzzy, and thud (source). The last one is definitely a keeper.

    struct Thud: Thuddable { ... }

    I remember the first time I was introduced to toto—the most used metasyntatcic variable in French programming literature—and made fun of how silly and immature it sounded; a shortsighted take in retrospect.

  40. Going Indie

    Today was officially my first day as an indie. Even though the timing might be less than ideal, I can’t help but feel excited about it—especially whenever I take a gander at my meeting-free calendar.

    I have drafted some plans leading to this, but I didn’t have a global pandemic in any of them. Silly me.

    Then again, a quarantine is exactly what I need to start chiseling away at one or two behemoth projects that have been staring me down for the better part of last year.

    Wish me luck. And f☆ck COVID-19.

  41. I am slowly starting to appreciate the versatility of the CSS Grid layout module. For instance, in this commit I replaced a flex grid that required finicky media queries and margin gymnastics with essentially three lines of code using grid. Here is a variable-free version of what I ended up with:

    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
    grid-gap: 1rem;

    The result can be seen here. Not only this achieves the exact same result as my previous flex solution, but it is cleaner and doesn’t use any media queries. Sign me up!

  42. Using Key Paths for Deduplicating Swift Arrays

    Today I needed to remove redundant elements from a Swift array based on the value of a specific property. After some foraging, I came across this post where Antoine extends Sequence to handle the more generic case of deduplicating elements that conform to Hashable.

    public extension Sequence where Iterator.Element: Hashable {
      func deduplicated() -> [Iterator.Element] {
        var seen = Set<Iterator.Element>()
        return filter { seen.insert($0).inserted }

    For my use case, I needed a bit more control over how the elements get deduplicated. Since I am only interested in comparing a single property, I resorted to key paths since they lend themselves quite well to this usage.

    public extension Sequence {
      func deduplicated<T>(
        by keyPath: KeyPath<Iterator.Element, T>
      ) -> [Iterator.Element] where T: Hashable {
        var seen = [T: Iterator.Element]()
        return filter { element in
          let key = element[keyPath: keyPath]
          if seen[key] == nil {
            seen[key] = element
            return true
          } else {
            return false

    And here is an excerpt from the code where I am using this extension.

    struct Game: Codable, Hashable {
      var name: String
      var releaseDates: [Date]
      /* ... */
      The API reponse returns a list of non-unique games separated.
      by release date, but for this view we only want a single instance.
      of each game.
    let games: [Game] = /* ... */
    let deduplicatedGames = games.deduplicated(by: \.name)

    For the name, I chose to not go with unique because it describes the elements of the sequence rather than the sequence itself. I instead took some hints from Rust’s similar-but-not-quite Vec::dedup.

  43. There is a new trend emerging in the design Dribbble community. And some creative souls decided to call it neumorphism.

    I have absolutely no qualms with visual experimentation, depth in user interfaces, or the specific effects used in this new trend. But I can’t help but feel put off by this incessant, collective infatuation with fads in UI design circles. It’s not healthy for anyone caught up in it, especially newcomers who have yet to find their creative footing.

    If you are just starting out as a UI designer, learn to ignore design trends. You can thank me later.

  44. Ten Years

    The beginning of a new year is often considered a good time to develop new habits or quit bad ones. The beginning of a decade, however, offers the less frequent opportunity to look back at a more substantial chunk of our lives and reflect on where to go next.

    Ten years ago, I had just landed a full-time contract as a junior product designer at a large telco company in Paris, France. My tasks straddled mobile product design, project planning, and community management. Even though the organizational unit where I worked was intended to function like an independent startup, the hierarchy, bureaucracy, and waterfall processes made it everything but.

    At the time, I had no clear career path in mind. All I knew was that I wanted to build mobile applications for a living. My “programming” experience prior to that was limited to Wordpress and Flash, and the labyrinth of memory management has consistently stood between me and learning Objective-C.

    After a year and a half in Paris, I moved to the US where I joined a local startup in the DC area, then thoughtbot in 2012. Working at the latter for a little over 4 years has drastically changed how I see software, both as a user, and as a maker. I eventually managed to overcome Objective-C, move to Stockholm, and change jobs twice since.

    During my job interview in 2010, I was asked where I’d see myself in ten years. I don’t remember the exact answer I concocted, but I remember it was utter nonsense. Ten years is a long enough time to make any attempt to predict the course of one’s life an exercise in futility.

    Where do I see myself ten years from now? Not the slightest clue. I might still be making software for a living. Maybe running a successful company of one, or two. Or perhaps I’ll find solace in cultivating the land.

    Only time will tell.

  45. IBM 💔 Server-Side Swift

    IBM has unofficially announced that they are abandoning Swift and their work within the SSWG starting 2020. Sad news, given that their stewardship of Kitura and clout in the enterprise market gave a much-needed credence boost to Swift in the server-side space.

    Four years since Apple open-sourced Swift and made it run on Linux, the ecosystem still has ways to go to stand on its own as a battle-tested stack that attracts developers from other established communities. With that being said, this process has been accelerated since SSWG started a little over a year ago; they since have been doing a remarkable job with reconciling different projects and focusing on key modular components that benefit the community at large.

    While this news is a bit of a setback, I firmly believe that server-side Swift’s best days are still ahead of it.

  46. Alexey Naumov in Performance Battle: AnyView vs Group:

    I cannot say there is a clear leader among AnyView and ConditionalView, but the myth about negative AnyView performance implication is BUSTED.

    I take most of what I see on Twitter with a grain of salt, especially when it’s technical advice that’s not backed by examples or reproducible benchmarks. In the case of SwiftUI, there is no shortage of guesswork and hearsay given how under-documented the framework is. And while I appreciate the openness, the occasional tweet from members of the core team is not enough to fill the knowledge gap.

    Luckily, there is always an industrious soul in the community that rises up to the task of winnowing the chaff from the grains.

  47. PeerTube 2.0

    The nice folks over at Framasoft have been doing a tremendous job with PeerTube in general, and this release in particular.

    For those unfamiliar, PeerTube is the Mastodon of video—a federated video platform that uses the ActivityPub protocol to connect multiple independent instances. Any individual or organization can run their own instance and have total control over their content and communities.

    I am very excited to see this platform evolve and get more traction the world over. Hating on YouTube is cliché these days, but the service deserves every bit of it. And then some.

    Now, I understand that people making a living out of content creation can’t move to other platforms willy nilly, but that’s exactly the reason why it’s important to get behind projects like these.

  48. Inset Grouped Lists in SwiftUI

    When SwiftUI shipped earlier this fall, it didn’t provide any APIs to use the newly introduced inset style for grouped lists and table views. The latest release seems to have addressed that, albeit silently and not in the way that I had expected.

    As of iOS 13.2, grouped lists will use the inset style when the horizontal size class environment value is .regular, such is the case with fullscreen scenes on iPad.

    Grouped Lists

    If you want to forcibly enable or disable this style, you have to manually set the size class environment variable, preferably directly on your list to avoid any unintended side effects:

    List {
      Text("Item 1")
      Text("Item 2")
      Text("Item 3")
    // To enable the inset style
    .environment(\.horizontalSizeClass, .regular)
    // To disable the inset style
    .environment(\.horizontalSizeClass, .compact)

    While I am not aware of any issues caused by this approach, I’d have preferred if Apple introduced a dedicated InsetGroupedListStyle or, even better, exposed the underlying ListStyle protocol instead.

  49. Embrace the Darkness

    Dark mode support for this website, fresh out of the oven.

    I have a soft spot for dark interfaces. So much so that the several instances I had to switch back to light mode while working on this made me feel inexplicably uncomfortable.

    Since I had already done the legwork of using CSS variable for the colors used throughout the site, it was relatively easy to implement this new dark theme. Here is the commit for those of you interested in the nitty-gritties.

    Currently the site takes the same appearance as the OS, but I am entertaining the idea of adding a manual toggle sometime down the road.

  50. Swift Server Work Group Annual Update 2019

    I absolutely love the work that the SSWG has been doing, and this annual update published by Tanner is a testament to this.

    The lack of consensus on how to write server-side Swift has been dividing its fledgling community; something that the SSWG has been working towards solving since its inception.

    I am hoping to be able to contribute more to this ecosystem, and I urge anyone who’s interested in making Swift more ubiquitous to do the same.

  51. As a developer, there are days when I feel fortunate to work with bleeding edge technology. It’s empowering, eye-opening, and above all, fun.

    Then there are days when I feel like I’m wasting a chunk of my life working with broken, undocumented, and unfinished tools that work against me at every turn.

    I’ve come to accept that living with this ebb and flow is an integral part of professional life in this field. But sometimes I can’t help but wonder if we can do without the high mental and emotional toll that comes with this churn.

  52. A Note About Assumed Audiences

    You might have noticed that I’ve been opening every Unredacted article with a sentence describing the assumed audience. The intention behind this is to help readers quickly determine if the content aligns with their interests, especially given the non-thematic nature of the blog.

    I first saw this pattern on Chris Chrycho’s blog, and immediately fell in love with it. The ability to juggle between the generic and the specific, the momentous and the mundane, the subjective and the objective, is the main selling point of a personal blog. This editorial freedom, however, often comes at the price of readership loyalty.

    Adopting this habit as an author should in theory alleviate the burden for visitors, both new and returning, to winnow the content to their liking.

    Granted, it’s not an exact science, and I welcome everyone—especially the curious among you—to read past the disclaimer even when it doesn’t appear to be an exact match at first glance.

  53. Update About Nope & Syndicate

    Nope & Syndicate

    Since Safari 13 was released last week on macOS, I’ve been getting an unusually high amount of inquiries about the status of Nope and Syndicate. This is the TL;DR of the response I’ve been copy-pasting so far.

    I’ve been planning to update these extensions since the deprecation announcement, but I haven’t managed to find the time to do that yet. This means that users who relied on either will have to find alternatives in the AppStore.

    Both Nope and Syndicate are open-source and will remain so in future iterations. While I don’t have a concrete release window yet, I still believe in the importance of investing in open-source, community-driven browser extensions and content blockers.

  54. Sneak peek of something I’ve been working on this past couple of weeks.

    SwiftUI Directory

  55. Impressions from the Apple Event

    Some of my impressions from the Apple Event from last Tuesday:

    • The intro video was fun to watch, for once.
    • Tim skipped the numbers update this time around. Good riddance.
    • Apple Arcade is at least 4 years late. I’ll bite, regardless.
    • Apple TV+ is cheaper than I, and many others, had expected.
    • While I got used to the notch, I could get used to not having it. Too bad it’s here to stay another year, at least.
    • Hats off for showing the name of the photographers and artists when showcasing photos and videos.
    • “It’s so pro.”
    • Save for the Watch’s always-on feature, the event didn’t quite live up to its title, “By Innovation Only.”
  56. On Truncating Feed Content

    While skimming my RSS subscriptions this morning, I came across this tidbit from NetNewsWire:

    On the Many NetNewsWire Feature Requests to Show Full Web Pages


    There is a solution to the problem of showing full content and not leaving the app, and it’s a feature that really does belong in an RSS reader: using content extraction to grab the article from the original page.

    If you’ve ever used Safari’s Reader view, then you know what I’m talking about. The idea is that NetNewsWire would do something very much like the Reader view (but inline, in the article pane), that grabs the content and formats it nicely, without all the extra junk that is not the article you want to read.

    Let me be clear about this: Truncating content in RSS feeds is, without a sliver of doubt, an accessibility issue first and foremost. Accessibility as in making your content accessible to your readers wherever they chose to subscribe to your feeds—be it a mobile app, a command line, or through a screen reader. Undermining this aspect and coercing them to visit your website, no matter how much love you poured into it, is short-sighted at best, and inconsiderate at worst.

    I get that authors need to pay the bills, and some of them resort to sponsorships or ads to do so. But it’s user-hostile to presume that your subscribers don’t know any better and that they can only enjoy your content directly on your website.

    Authors who care about their readership have already figured out perfectly legitimate ways to monetize their feeds without any content truncation. Those who don’t are unlikely to bother and will continue to do a disservice to their readers.

    In the meantime, industrious developers will keep finding workarounds to restore functionality that users yearn for. And nothing can stop that, because open always wins.

  57. I’ve been running into several abstruse issues when smoke testing this website’s feeds in some RSS readers, including the newly released NetNewsWire 5. Upon further investigation, I found out that due to a glaring misuse of some Node.js APIs, all URLs have been missing a / after the https part1.

    The bad news? Once the fix is deployed, most RSS readers will reset the read status of the entire feed, since the individual entries are uniquely identified by their URLs. What’s worse, readers that cache previous entries will end up with duplicate content.

    I apologize for the inconvenience that this might cause and promise to be more careful to avoid syndication-related bugs like these in the future.

    1. For the curious, I inadvertently used the path.join(…) method instead of url.resolve(…) to construct these URLs. The former is only supposed to be used in the context of file system paths, not URLs.

  58. By default, git fetch gets an updated list of remote branches from the remote and sets up remote branch references locally. However, it doesn’t delete stale references that no longer have a counterpart on the remote. Trying to get rid of these using the git push -f origin:branch-name command will fail with a remote ref does not exist error.

    To delete stale remote references, you need to pass the --prune option to fetch like so:

    git fetch --prune
    - [deleted]  (none) -> origin/branch-name
  59. On Keeping SwiftUI DRY

    If we were to represent the hierarchy of our refactoring itches as a pyramid, eliminating duplication would be at the very bottom. The DRY principle, as it is often referred to, is the uncontested cornerstone of good development practices.

    SwiftUI, as new and unpolished as it is, already exposes some powerful APIs for that end. We’ve been using view extensions, view modifiers, and preference keys on a constantly growing codebase at work. If you’re looking to learn more about these largely undocumented capabilities, look no further than these two fresh posts:

  60. @kaishin onPreferenceChange() did not change 😉 It always required Equatable (how would it detect changes otherwise!). What did change though, is that Anchor no longer conforms to Equatable 😕

    — The SwiftUI Lab (@SwiftUILab) August 3, 2019

    I previously assumed that onPreferenceChange(_:perform:) added the Equatable requirement, but it turns out that Anchor<Value> dropped its Equatable conformance instead, as pointed out by @SwiftUILab and the official documentation.

    A curious change, regardless.

  61. Undocumented View Preference Changes in Beta 5

    Update: My assumption was wrong. Corrected here.

    I haven’t seen this mentioned anywhere, but the onPreferenceChange(_:perform:) view instance method now requires the preference key value type to conform to Equatabale as of Beta 5.

    In practice, this means that oPreferenceChange can no longer be used with preference keys that have an Anchor<Value> as their value type or a as a property of their value type, since Anchor itself doesn’t conform to Equatable. I fixed this by passing the GeometryProxy instance to a custom view modifier that unpacks the anchor first using the provided proxy, then passes the result as a CGFloat instead.

    For more on preference keys and anchors check out this informative blog post series.

  62. My Screen Time breakdown for last week. The time I used to spend on Twitter and Mastodon has shifted to reading, writing, and—ahem—browsing Reddit.

    Screen Time Summary

  63. Hello, world.

    Not long ago, I started toying with the idea of rolling out a custom-built microblog instead of relying on third party platforms. Today, I am happy to launch a modest first iteration.

    I will keep my single-user Mastodon instance and Twitter for the time being, but I will use them mainly to syndicate posts that will be published here first.