Tom Insam

Apple Photos

Photos: “Here’s a favorites album! You can put the photos you like the most in it! There are other albums, and you can share the whole library with your family, but not your albums. Apart from the favorites album, you have to share that one.”

Watch: “You can sync any album of photos you want to your watch! But just one.”

Lock screen: “You can have a rotating collection of photos on your lock screen now! What’s that? Albums? Favorites? What’s an album? Nah, I’ll pick the photos for you, but I have magic, so I know you’ll love them. I don’t care what you marked as favorite. And no, if you actually like one of them, I won’t show you where it is in your library, that would be too easy. No, you can’t just use an album.”

iPad lock screen: “Hahaha no.”

Watch: “Magically chosen photos that you’ll love? Interesting! No, you can’t use those. Just albums.”

Photos: “No, why would you want to see the specially curated list of magical photos the lock screen thinks you’d love? That’s absurd. Here’s a set of unrelated Memories that I know you’ll enjoy.”

Lock screen: “Don’t be silly, you can’t put Memories on the lock screen, why would you want that? My selection is better.”

Watch: “Sure you can have Memories on the watch! No you can’t pick which one.”

Third party API: “No of course you can’t let users pick photos from any of these curated lists, that’s silly.”

[This is a lightly-edited flow-of-consciousness thing taken from a slack conversation]

Is it worth trying to write complicated Codable implementations in Swift to map your network model to the local business model you prefer? It’s a lot of complicated code, but maybe having a single representation of your data is worth the trade-off.

I hate doing it, but no. I always end up with a network model and a database model and a “used in the app” model and mapping methods between them.

I hate it because it’s irritating, because the models are always almost the same as each other and it grates maintaining the conversions which are always boring 40 line functions of self.foo = other foo over and over. (At least now we have swift you don’t get weird bugs where some of your mappings forget to instantiate all the properties.) It feels like it should be possible to build a magical perfect object that you can decode from the wire and then put directly into the database, then pull it out and power the UI from it.

But the Codable example is an excellent demonstration of why you can’t really do that. Your wire protocol isn’t quite what you want, so to have a wire object that’s also your business object you need to write a ton of Codable conformance code. (You can’t write just a little bit - Codable auto-conformance is all or nothing.) In fact, you need to write so much code that it would be easier and more maintainable to just write a simple-as-possible wire-format Codable container and a mapping function. For all intents and purposes the Codable conformance is a wire format object, you’re just writing it in an inconvenient syntax.

Your database representation needs to be much flatter than the business object - your model is a deep structure but you don’t want 300 tables and 600 joins so you need to flatten out the deep object to a single table - you’re doing the same thing with custom SQL statements to serialize and un-serialize your rich object, whereas a flat object and a mapping could write to the table without custom code, and would be easier to read.

And that’s even before getting to things like “it would be super convenient if my view data models were immutable, so I can use swift UI / redux” but core data models are not only mutable, but some other thread can mutate them for you with no indication that things changed unless you’re explicitly observing for that sort of thing.

More complication - there are actually 2 (sometimes 3) network representations, because you sometimes need to send objects back to the server. The create call (normally) won’t have, say, an object ID or a created date, but those properties are non-optional on your network model for incoming objects, so your create call object is different from the get call. And your update call probably wants everything to be optional so you can update only one property at once.

So no, your life will be easier if you just write multiple specialist representations of your objects for different contexts, keep them all as simple as possible, and write mappings between them.

Diablo Immortal

I’ve been playing a certain amount of Diablo Immortal. I’m coming to it as someone who enjoys Diablo 3 and has played a lot of it on both PC and console. I’m enjoying it. Very happy to have a game this polished on mobile, frankly. There’s a ton of story-driven game here without needing to pay, and it feels like a Diablo game.

The whole game feels like Diablo 3 but sanded down hard. It’s smoother, fewer annoying corners, but it’s also… less now.

Things I like - loot autopickup is great, the salvaging interface is a ton better, the footprints are actually pretty nice. I like the auto-navigation in zone once you’ve demonstrated mastery of that zone. I quite like the 2-tier gems/loot thing where the important parts of the loot are differentiated from the stat sticks. The controller interface is pretty good compared to D3 as well, though D3 is already pretty good. Inventory management is much better than console, though that’s because there’s a touch interface.

Two obvious places where DI is worse than D3 - maps are waaaay smaller (feels like the bad console generation games we had where every cross-platform game on every platform was constrained by the RAM of the original xbox) and the fact that the loot is flattened out - by 30 everything I’m wearing is yellow and even progressing I’m not getting blue drops that are better, so now everything that drops is just trash. I do have one legendary with a skill-specific thing on it (it boosts multishot) so the general sense of the D3 loot system is still here, but the affixes are much simpler - they seem to boost a skill in a simple fashion, and nothing else. There are simple synergies but nothing like the amazing post-level-cap scaling of Diablo 3 (which makes sense! This is an MMO, you can’t allow that sort of scaling in your player base, you need them to be in one flat progression tier with minor differences between them gated by raid progression). I hate that monsters leash now but, again, MMO, sure.

The skills have been simplified a ton - probably too much, there’s a lot in the D3 skill system that I like but there were also a lot of skills that were pretty much useless and noone would ever use. I like the cooldown system rather than the energy pool - it means there’s an incentive to use everything you have slotted because it doesn’t hurt use of the other things you’re running.

The open world thing is interesting, in that I see players shooting furiously at thin air a lot presumably because they’re fighting quest-specific monsters but they’re not themselves instanced.

Oh, and of course there’s all the obvious complaints - it’s free to play and progression will therefore inveitably eventaully be awful (though there’s a lot of good free gameplay in here), the progression mechanics force you to engage with the social stuff (the game is requiring me to join a “warband” to progress, whatever the fuck that is), the UI is covered in little red dots and there’s a bunch of “log in every day to tick the boxes” overhead (though it’s not like endgame MMOs don’t have dailies. Getting users to come back every day isn’t just a f2p thing).

No True AI

Shower thought, but I’m getting a certain amount of “no true scotsman” vibe from my twitter stream recently about AI. “Even if it does pass the turing test it’s not sentient” which is interesting! When people are presented with something that passes the previously impossible-to-approach barrier they set, do they accept that it passes the barrier, or was the barrier wrong? Were we just not really seriously considering the barrier as a good test until something arrives to challenge it? Or is it an indication that the entire problem is bad? Why does this test matter? etc. We just don’t believe in intelligent computers as a society, and so pre-writing a test decades ago doesn’t help at all, because we’ve used the test until something “passes” it (to be clear, this expert system is not intelligent, but that’s not the interesting thing here) and as soon as something passes it we’ll move the test.

Feels somewhat like the mistake of the google engineer is that they jumped from “I can have a conversation with this” to “therefore we should never turn it off and it should be allowed to vote” and when/if intelligent machines arrive they’re not going to get that. I have a feeling that (assuming we can build intelligence) we’ll end up with star wars droids - intelligent, have personalities, you can make friends with them, they’ll have wants and dreams, but at the same time absolutely everyone in society (including the droids) accepts/assumes that they’re slaves / property / subhuman and have no rights.

Egyptian calendar, dating system established several thousand years before the common era
...
[It] consisted of 365 days organized into 12 months of 30 days each [..] There was apparently no attempt to introduce a leap-year day to compensate for the slippage of one day every four years; as a result, the civil calendar slowly rotated through the seasons, making a complete cycle through the solar calendar after 1,460 years.
..
The Egyptian civil calendar was altered by Julius Caesar about 46 BCE with the addition of a leap-year day occurring once every four years.

Egyptian calendar, Encyclopædia Britannica

I’m building things with a combination of the new Room ORM and Data Binding, and I find that when Room has compile errors they express as hundreds of lines of Error:(6, 31) error: cannot find symbol class BR and related things, and no actual real error.

Turns out, javac will print a maximum of 100 compilation errors, and when dealing with preprocessors you often want the last error message, not the first. Put this in your top-level build.gradle file and become happy:

allprojects {
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xmaxerrs" << "4000"
            options.compilerArgs << "-Xmaxwarns" << "4000"
        }
    }
}

Code Points

A commonly touted disadvantage of UTF-8 is that string indexing is O(n). Because code points take up a variable number of bytes, you won’t know where the 5th codepoint is until you scan the string and look for it. UTF-32 doesn’t have this problem; it’s always 4 * index bytes away.

The problem here is that indexing by code point shouldn’t be an operation you ever need!

[..]

Unicode itself gives the term “character” multiple incompatible meanings, and as far as I know doesn’t use the term in any normative text.

Let’s Stop Ascribing Meaning to Code Points

Electric Objects EO2

I just bought an Electric objects EO2. First impressions:

  • It's exactly as pretty as I was hoping for. Which is to say, very pretty.
  • It's heavier than I was expecting. I'm renting, and I'm not quite ready right now to put the holes in the wall that mounting it would require (though the instructions and mounting kit are themselves lovely). Someone thought about this, and the frame has lovely little grippy feet on the bottom so it props up nicely against the wall and doesn't feel unsteady at all.
  • Auto-brightness is off by default. The lowest brightness setting still feels a little high, but that might just be my perception of it because it's so new. Update 4 days later: Nope, brightness is perfect. It never feels like it's glowing too much, and the lowest setting when the room lights are out is very low indeed.
  • Anything animated that's not really subtle drives me crazy. I've never been able to handle having a moving screen in my peripheral vision, and this absolutely counts. But tiny subtle animations are just lovely. Before it arrived I'd assumed that I would almost resent using what is essentially a computer to display still jpegs, so I'd stockpiled nice animations, but in practice it displays those jpegs so well that I'm just as happy with still images.
  • The iOS app for photo and playlist management is... functional. I imagine that I won't be using it a lot as I settle into the things I like, but initial setup is a drag of stuttering scrolling and loading screens.

And here are the nerdy developer things I wanted to know before I bought it:

  • It's an Android device, running some AOSP-like fork of 4.4.2. No Google Play Services, obviously.
  • There's a micro-USB socket on the back of it, and ADB, etc, work just fine. "adb shell" gets you a root shell.
  • You can side-load anything you feel like.