Instantiating an Abstract Class with Dependency Injection

In my Laravel app, I wrote an abstract class that has a fair bit of stand-alone behaviour. I wanted to test this directly instead of via the implementations.

PHP has anonymous classes, so instantiating it isn’t very tricky to do in a unit test. But the constructor also has about a dozen dependencies its asking Laravel’s service container for, and I wanted [almost] all those to be injected for me.

Problem is, I don’t think PHP lets you create an anonymous class and assign it to a variable, without instantiating it at the same time.

Instead, I found a clever trick: I can implement my own constructor and use App::call() on parent::__construct.

new class extends WorkflowFromJsonRepository {
    public function __construct()
    {
        App::call(parent::__construct(...), [
            'someParamToStub' => $stubbedThing,
        ]);
    }
};

If you need to pass stubs in, you can pick and choose by passing them in the second call() parameter. Ya’know, standard Laravel stuff at that point.

I am not sure if this trick would works on anything below PHP 8.1. The syntax with the three dots — parent::__construct(...) — is the new first-class callable feature. I’m not sure if you can get a handle on that using the older array-based syntax?

Garrick the Lightbringer

This is a short story from our current Dungeons & Dragons campaign. This is the moment when my warlock greedily took up an artifact after passing its guardian’s trial.

Garrick loved leaning on borrowed power. In this instance, the power he sought to take took him instead.

This story contains spoilers for the Baldur’s Gate: Descent into Avernus adventure. Some components may be gruesome. You have been warned.

More

Wake up your RDS Aurora Serverless before running your migrations

When you’re using an RDS Aurora Serverless DB instance with Laravel Vapor, you have the option to scale it down to zero capacity units when it’s been idle. This is great for development environments — it only takes a few seconds to come back up, and while it’s hibernating, you’re saving loads of money.

One downside is that your migrations may fail during deployments. When Vapor goes to run the php artisan migrate command, RDS often won’t wake up before Laravel’s DB connection attempt times out:

An error occurred during deployment.

Message: Deployment hook failed.
Hook: migrate --force

In Connection.php line 678:
                                                                               
  SQLSTATE[08006] [7] timeout expired (SQL: select * from information_schema.  
  tables where table_schema = public and table_name = migrations and table_ty  
  pe = 'BASE TABLE')                                                           
                                                                               

In Connector.php line 70:
                                       
  SQLSTATE[08006] [7] timeout expired  

I wrote an artisan command to poke the DB a couple times, and added this to my vapor.yml as its first deployment step.

<?php

// app/Console/Commands/WakeUpDatabase.php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class WakeUpDatabase extends Command
{
    protected $signature = 'db:wake {retries=5 : attempts to make} {wait=5 : time to wait between retries, in seconds}';
    protected $description = 'Wakes up a potentially-inactive serverless RDS database';

    public function handle()
    {
        $retries = (int) $this->argument('retries');
        $wait_between = ((int) $this->argument('wait')) * 1000;

        retry($retries, fn () => DB::select('SELECT 1'), $wait_between);

        $this->info('Database is up');
    }
}

Add php artisan db:wake to your vapor.yml deploy: section, right above the migrate command, in each environment you have an Aurora Serverless DB.

Problem solved!

Torghast, Tower of the Damned

Torghast, the Tower of the Damned, is a rouge-like (ish) set of dungeons in WoW: Shadowlands. I finished the “hard mode” last night and got my Maw horse, so I wanted to write up some of my thoughts on the feature.

If you read “rogue-like” and think angband or Caves of Qud: congrats, you’re old and curmudgeonly like me! But also wrong.

This is much more akin to Hades: you play your character normally, but you make decisions about which buffs to take. If your build sucks, you get wrecked by the boss and you start again from scratch.

I’m writing this from the perspective of my main, a marksman hunter. I’ve cleared the “regular” Torghast wings as an arms warrior as well, but I’ve only experienced the hard mode, Twisting Corridors (TC), on my hunter. I was clearing Torghast before they brought the scaling down to more rational levels.

Anima Powers

The anima powers in Torghast promised to be fun and varied. Your rotation would change based on what powers you chose, and they’d be able to do really out-of-this-world stuff.

I don’t think Torghast really delivers on that.

As an MM hunter, there are two powers that change my rotation: igniting the tar trap for an AoE, and using binding shot for a short crit buff.

The first couple runs, I thought they were great! And then I realized that was it — there weren’t more cool powers like that coming; I’d already seen them all.

Making things slightly worse, the binding shot power is incredibly difficult to proc when I’m in a party, since the mob has to move out of the affected area to trigger the effect. I wasn’t usually on voice comms to ask the tank to reposition, so I’d have to use my knockback, annoying everyone.

The other hunter powers buff abilities you’re already using. You need some amount of aimed shot / kill shot buffs to keep pace with the dungeon’s HP scaling, but those are not exciting choices.

Marksman hunter in particular gets a raw deal: there are a bunch of powers that buff your pet’s damage. As MM, I’d only have the pet out when I’m solo, and it’s for tanking. It has anemic damage — +20% of 0 is still 0.

The worst example of an anima power is the Neural Pet Enhancer: +500% pet damage when you give up control of your character and directly control the pet. +500% of nothing is still nothing, and I’m giving up the majority of my damage, while also leaving my body unattended and vulnerable to death.

Some runs, that power comes up so frequently as an option that I have started to wonder if taking it is the correct choice. At least that way, I’ll stop getting a completely worthless power wasting one of the choice slots!

There are no pet powers that actually do anything helpful for MM. To increase pet health, you increase your own health. There’s nothing specifically to make the pet tankier, improve mend pet, or interact with any of your abilities.

I don’t feel like I’m making choices to build around something. Every single TC run, I end up with the same set of powers, because those are the only powers that exist. The biggest differentiator is powers from rares, but those end up being passive powers that don’t change your gameplay anyways — they just scale your damage up.

The RNG

What anima powers drop, how many souls you free (for +1% primary stat each), and what boss you get are all random.

In regular six-floor Torghast, this can royally fuck you: maybe you won’t get enough soul remnants, or maybe you’ll get mostly defensive powers, or maybe you’ll get a boss that needs to be interrupted more frequently than your spec is capable.

Torghast, like similar games, has a shop mechanic to mitigate that. But the shop only had a couple randomly-selected common powers. In the regular six-floor Torghast, I generally can’t use this for a big power swing: you can buy a couple things. It’s not guaranteed to offer at least one defensive, offensive, and utility option either. Your shop can be all utility, which sucks if you need damage!

In Twisting Corridors, the shop is a bit better since you’ll see it six times instead of twice. There’s a lot more potential for getting an anima lure — either forcing one with the Ravenous Anima Cell, or getting the +25% phantasma one at random — so after the first shop, you can probably buy up the whole inventory every time.

I think there’s more that could be done with the shop to reduce folks’ frustrations with Torghast. Having limited options there is part of the whole roguelike shtick, but it just seems kind of unhelpful in regular Torghast and trivial in TC.

The boss is another thing left up to the RNG, although you get a heads-up in which it’ll be half-way into the run. This is probably so you can prepare for that boss’ mechanic, but in practice it’s useless information since you’re just going to go ham on damage powers anyway.

There are a couple bosses that are nasty, even after the scaling adjustments. Patrician Cromwell is a notable example, casting an interruptable AoE damage spell frequently. I’m guessing it isn’t too bad as melee, since your interrupt CD is short, but it’s unavoidable damage for specs with medium- & long-CD interrupts.

Hitting a wall on the boss sucks, especially when it’s a wall you couldn’t build around. If there was an anima power to make my interrupt CD shorter, or apply a silence, that would be one thing — but I don’t think any spec has powers like that? — so being told what boss you’ll be fighting half-way in isn’t actionable information.

Floor Layouts & Monsters

The floors in Torghast are not procedurally-generated. There is a set of possible pre-built floor layouts, and it’s not a very large set. I think there may be a couple floors with procedural elements, but I may just be imagining that.

After you’ve done the 128 floors required to complete TC, you’ll have seen every floor plan Torghast has to offer. Repeatedly.

Similarly, the monsters don’t have random affixes or anything like that. There’s a set of mobs associated with each tileset. You will have seen everything before you’ve finished regular six-floor Torghast.

I’m hoping both of these get remedied in future patches. A tileset affix (similar to M+) with some random per-mob affixes (similar to Diablo) would help with everything feeling the same.

Solo vs. Grouping & Scaling

After they scaling adjustments a few weeks ago, the whole group vs solo thing doesn’t seem to matter much. Prior, going in with a full party was substantially harder than solo — the mob HP would scale up higher — but that’s no longer a problem.

I did the first three layers of Twisting Corridors solo, and I didn’t have any trouble as MM hunter. But I’m bringing a medium-CD interrupt, a tank pet I can heal indefinitely, offensive dispels, hard CC, snares, and a root. With that kit, I can slice up packs, negate all of their special stuff, and generally never take damage.

After TC L3, I ran with a full party. I was a bit concerned about getting a nasty boss like Cromwell or Maw of the Maw and not having enough interrupts on my own, wasting the ~2h it takes to get up to the 18th floor; having a full group alleviates that.

In TC, the scaling isn’t really that bad until after the 2nd boss. You can survive hits from traps and hard-hitting boss mechanics up until the 12th floor, but you need to have your shit together as soon as you step onto floor 13.

I did not really notice much changing as I ascended from TC layer one to layer eight. It seemed to take about the same amount of time. Maybe the mobs had more health, but our damage scaling kept pace. Even on my layer 7 run, when we only had ~50 soul remnant stacks (as opposed to a more typical 80-100), we were able to complete the boss without feeling pressured.

It’s worth noting that the soul remnant buff (+1% str/agi/int) will boost your Spectral Flask of Power buff. I assume the two Shadowlands feasts will be buffed too, but I haven’t checked that.

It may be worth swapping a trinket out if you’re normally using one with secondary stats on it, since you should scale better with primary stats in the trinket slots. The same may be true if you have higher ilvl gear for a slot that you’re not using because it has the wrong secondaries. There are still lots of powers that scale mastery/haste/crit by a percentage, so I would not declare this as a hard rule.

The Traps

Torghast features traps. These are generally not a well-loved feature in any game I’ve played (lookin’ at you, Path of Exile), since they’ve got the potential to instantly murder you.

Some of the trap hallways can look overwhelming and terrifying the first time you see them, featuring rows of swinging axes between walls of fire. But they’re not that bad once you get used to them!

The long hallways of traps are made much easier by turning your camera so you’re looking at the walls. This lets you see exactly where you are in relation to the axes & fire/spike lines. You can each individual element one-at-a-time. The swinging axes don’t extend beyond their model, so you can stand to either side of the scrape mark on the floor and be safe while you wait for the fire/spike to come up.

The metal lines on the floor that shoot a white ball of energy down the track are trigged by proximity. Walk up to the very edge of the track, and then pause. It will fire the energy ball, and then it has to “reload” for several seconds, giving you time to cross safely.

The only tricky one is the grid of fire nozzles that typically blocks a doorway. This trap indicates which nozzles are going to shoot fire next with a subtle red highlight, so you can plan a path.

I never plan a path, since I have the Night Fae blink — just know that the blink is not long enough to clear the entire thing, so you have to blink from one nozzle into the trap. There’s a paladin power that gives bubble to the whole party; this is a good spot to use it, since someone will inevitably die to this trap.

Some of the traps have off buttons, so if you’re through first, turn around and look for a lever on the floor or a switch on the wall.

And if you do get hit by something, check to see if it left a DoT on you. You’re not in combat, so you can eat to out-heal the DoT.

Good Specs for Torghast

I do not have an exhaustive list of “Torghast spec rankings”, just my observations. I don’t think I’ve run it with most specs, but here’s what I found noteworthy:

  • Night Fae Balance Druid: In a party, this will be your top DPS. I suspect balance will struggle a bit solo, since it lacks hard CC and has a long-CD interrupt — but in a party, all they need to do is drop moons on things.
  • Vengeance Demon Hunter: With a couple powers that buff Immolation Aura, they’ll put the DPS to shame.
  • Mistweaver Monk: Between touch of death and the anima power Wrist Wraps of the Zen Master, they’ll wreck the DPS on AoE pulls.
  • Mage: The Echoes of Elisande anima power makes time pass faster during Time Warp. This is like super-haste, even decreasing your CDs. Your burst goes through the roof, and it’s really fun.

I would add that marksman hunter kind of sucks in a party. I was very strong in the early floors of a TC run, but my damage scaling didn’t keep up with other specs.

I’d say MM should lean into being a support class: get the power that gives your misdirect target +100% damage done and -90% damage taken, make your hunter’s mark increase damage done by everyone, and dispel everything.

The Cilice of Denathrius

The Cilice of Denathrius is an anima power that sounds like an absolutely awful choice on the first floor of a Twisting Corridors run:

Gain an additional 15% damage and healing when you ascend to a new floor of the Jailer’s Tower.

Lose 5% max health when you ascend to a new floor of the Jailer’s Tower.

The Tooltip

In my layer 8 run, the moonkin chose this, perhaps without reading the negative effect. We pointed this out, and this began a chain of hilarious events.

The entire run was focused on buffing the moonkin. They needed to grab HP powers. I was misdirecting to them for the short +100% damage buff, the tank took group defensives to better protect our glass cannon, and so on.

It was fraught for a bit. There were a couple floors in a row where the moonkin didn’t find any good defensive powers, and dipped down into the low 20k range.

When we got to the boss on the 18th floor, it died in about twenty seconds. The moonkin did fairly well with 55k HP going into that, but they did a shocking 1.07m DPS and obliterated the boss before any AoE or incidental damage could touch us.

Image
Boom. Thanks, Skydín.

This was a high risk strategy, but it paid off. It’s what I hoped to get out of Torghast, so I’m glad I got it out of my last Twisting Corridors run.

Effort vs Reward

The biggest problem with Torghast seems to be the effort it takes compared to the reward you get. In the normal six-floor Torghast, a layer 8 run seems to take about an hour. This isn’t too bad, but you can fail and walk away from the run with nothing to show for it.

Twisting Corridors is much more punishing: you don’t get soul ash despite a run taking upwards of two hours. You only get stuff on the even-numbered layers, which feels absolutely terrible — two hours spent on any other activity would yield gear, or at least some anima. Would it have killed them to make a one-time pet reward for every layer?

The whole thing feels incredibly unrewarding, especially if you fail the run and walk away with nothing.

I think the difficulty of regular Torghast on layer 3+ before the scaling changes has resulted in a bad first impression. I know a couple people who are bitter about being forced to do it for legendaries after failing a few runs early on.

Failure needs to be less punishing than “ha ha, you’ve wasted your time, get fucked!” to bring those folks back into the fold. Maybe a little soul ash off the floor bosses? Or just bringing run time down to the 20-30 minutes range, so you feel like you can get back in instead of feeling like the whole evening has been a waste and log off.

This is a missing aspect from the genre Torghast is drawing from — you’re supposed to die a lot, but death still offers you a power-up for next time. If Torghast had some kind of persistent progression system to power you up, failure wouldn’t feel like a waste of time.

Of course, the “persistent progression system” for Torghast is supposed to be gearing up. But you don’t make any progress towards gear if you fail.

Before the scaling changes, I thought putting Torghast into the Great Vault would make sense, with the metric to unlock stuff being the number of floors cleared. Even if you couldn’t finish a whole layer 8, you’d get a consolation prize for the run on Tuesday.

After the scaling changes, I don’t know if that’s still appropriate. Instead, maybe floor bosses could drop something like an augment rune that only works in Torghast? Stock up enough, use them for a stacking buff, and you’ve got yourself a big advantage — kind of like the buff you get for wiping in LFR?

The last issue with rewards, specifically from Twisting Corridors, is that I will never get anything from it again. I’ve gotten the one-time rewards, but I’ll certainly be going back at some point to help folks clear it.

I like Torghast well enough, but it really sucks that I’ll be spending hours on it with no prospect for anything.

Torghast as Leveling Content

Torghast is not available for alts to level with in Threads of Fate.

This really sucks. I got my arms warrior up to 60 and wanted to make my first-tier legendary. This required me to spend a day unlocking every single layer for regular six-floor Torghast.

I think we’d be a lot better off if you could do Torghast runs for XP. Even if you aren’t eligible for Soul Ash until level cap, you can still get layer 8 unlocked. Then, you just need to do two runs for your ash.

Miscellaneous Tips

Here are a few Torghast tips that didn’t fit anywhere else in this post.

  • Don’t select your initial power until everyone loads in. Otherwise the slow loaders don’t get an orb. This is probably a bug, but…
  • Save the floor boss for last! If someone dies and releases AFTER it’s defeated, they’ll spawn on the next floor and miss out on the powers/phantasma that they haven’t looted.
  • Using the ravenous anima cell on a Mawsworn Acolyte, Mawsworn Disciple, Mawsworn Endbringer, Mawsworn Soulbinder, or Lumbering Creation will boost your phantasma gains by a lot from the little skeleton adds.

Conclusions

Torghast is a good addition to the game, but it needed more time in the cooker.

The shortcomings it has can be addressed by adding more stuff. It doesn’t need a fundamental rework or anything, just more variety — more mob types, more floor plans, and more powers.

The Beasts of Prodigum event will be starting soon, which adds some new stuff to Torghast for a little while. I have not played with it yet, I think this is a great idea. It would be fantastic if Torghast could always have something special like that running.

The time spent vs. reward is out of whack too, but as long as we need legendaries, we’re stuck with that problem. We’ll see how it gets handled in patch 9.1.

FEW Spirits’ Cold-Cut Bourbon

I had somehow missed the release of FEW‘s cold-cut bourbon in 2019. Fortunately, somebody notified me about it last month.

I don’t usually go for FEW’s whiskeys — or those from the other Chicago distilleries — for one simple reason: Chicago & Evanston only re-started granting distillery licenses in 2008 and 2011, respectively. They’re new distilleries, so they haven’t had time to age the whiskey.

They have used cold-brew coffee to cut the cask-strength hootch down to bottling proof. That’s damn clever, so I figured I could make an exception to my “no local whiskey” rule in this case.

The bourbon-y and cold brew flavours are balanced really well. It’s impressive that they managed to get this right — cold-brew coffee can vary so much. But you can clearly taste the whiskey and the coffee, so major props to FEW. There’s a nice long aftertaste of coffee and bourbon.

I did not love this on its own, though. There was a flatness to the whole thing. It really felt like it needs some sweetening to reach its full potential. And that’s fine with me: I bought it mostly for cocktails!

So far, I’ve only done a riff on an old fashioned, with chocolate bitters. As I had suspected, the syrup took care of the flat note. It was very pleasant, and I highly recommend it. The recipe is below!

FEW cold-cut bourbon, chocolate bitters from Scrappy's Bitters, a jar of Luxardo maraschino cherries, and a jar of sugar cubes.
I don’t actually use sugar cubes for cocktails, but they sure look nice in pictures!
  • 2 oz FEW Cold-Cut Bourbon
  • 0.25 oz 2:1 Simple Syrup
  • 3 dashes Chocolate Bitters

Put everything into a stirring glass. Add ice and stir until well chilled. Strain into a rocks glass with fresh ice.

Garnish with a maraschino cherry or an orange twist.

I’ve got some other ideas for cocktails to use it in. Next up, I’m going to try pairing it off with china-china liqueur, which is orange and vaguely bitter. I’m trying to dig out from under all the wine Bright Cellars (disclaimer: that’s a referral link!) has been sending me, so I haven’t been mixing up as many drinks as I normally do.

As an aside: once the coronavirus is slain, I need to go re-take the FEW distillery tour. I used to have a pair of their branded glencairn glasses, but one ended up in an unfortunate collision with a water bottle, and its twin is chipped. The FEW tasting room is the only place I’ve seen them.

First Thoughts on Baldur’s Gate 3

I started Baldur’s Gate 3 on Tuesday afternoon. This morning, I “completed” the first chapter, which is the end of the story in early access. So here are my thoughts on it so far!

Firstly: the timing of the release was great. My Eberron campaign came to an abrupt end last Friday when we accidentally let Sharn get destroyed. Our DM couldn’t find any good Eberron 5e content for higher level characters (we’d just hit level 8 by destroying Sharn 😂) that didn’t require Sharn to exist, so that was a wrap.

Instead, we’re starting a new Descent into Avernus campaign this week. That adventure begins in Baldur’s Gate, and BG3 picks up at the end of the Descent into Avernus adventure. So that’s a cool tie-in!

The story in the game is awesome. If you’ve seen the cinematic, you know a nautiloid flies over Baldur’s Gate and kidnaps a bunch of people for processing. This is awesome. They’re unloading a lot of DnD’s coolest stuff right in the first few seconds: mindflayers, spelljammer ships, and ceremorphosis.

The goal of the game (or at least for the early access story) is to get the mindflayer tadpole out of your head before it turns you into a mindflayer. There seem to be lots of ways to do this. At one point, I think I had six different quests to find potential cures. There’s probably more, but my mostly-lawful-good choices closed off some less-savory solutions.

It seems like you can choose not to remove it too. You get some freaky powers from it, and using them does seem to cause some long-term effects. I mostly avoided using them since my character was firmly in the “nope nope nope” camp.

The first major town you end up in is a druid grove full of tiefling refugees, under threat from some goblins. The tieflings are there because they’ve been kicked out of Elturel for being a bit too demonic. Elturel is the city that ends up descending into hell in the Descent into Avernus adventure. I love the tie-in.

But there are tons of options here. You can help the refugees fight, or help the druids get rid of them. I think you can even join up with the goblins and destroy both the refugees & grove. There’s lots of little storylines and interactions. I spent a couple hours just talking to people and looking around.

Issues

This is an early access game. It’s not done, and they’ll hopefully be making tons of improvements to everything I’m about to raise as a point of criticism.

As far as bugs go: it’s not that bad! You start to see more rough edges when you finish up with the goblins/druid grove. But I had way more problems with Pathfinder: Kingmaker at launch, so BG3 is pretty solid.

I haven’t done any multiplayer. They’ve done three patches since release on Tuesday, and they mostly seem to be fixing multiplayer things. So you might wanna hold off if that’s your thing.

Now: the game is supposed to be the DnD 5e ruleset. It’s been bastardized a bit, and in some respects it’s not a positive change.

For example, shove is supposed to be an action, replacing your attack. In BG3 it’s a bonus action. This lets every character yeet an enemy on pretty much every turn, while still dealing damage. It’s supposed to be 5 foot push, but in BG3 it’s definitely…more. It feels a bit cheesey to win so much by yeeting people to their deaths. But it is hilarious.

A larger issue is the prolific use of surface effects, like patches of fire and ice. This studio’s other big game is Divinity: Original Sin 2. It prominently features making patches of Bad Stuff for people to not stand in. It’s toned down from D:OS2, but there’s still a lot of surface stuff in BG3 — too much for DnD 5e, honestly.

I don’t mind the occasional barrel of oil. That’s something I can identify and plan around at the start of combat. But it feels like every single foe has a fire arrow or a bomb to throw at me that leaves crap on the ground. After a round because everything is on fire. That’s doesn’t feel like DnD 5e combat to me. BG3 needs to pull much further away from DOS2 here.

What’s worse is a lot of spells leave patches of crap on the ground too. For example: fire bolt. In the 5e rules, when you shoot it at someone, it does 1d10 damage. That is all. In BG3, it does a weaker 1d6 damage, but leaves a patch of fire under the enemy’s feet + a burning condition (I think?).

That’s fairly counter-productive: I want my wizard to do some damage from the back while my martial characters are in melee range. It’s hard to be in melee range when your allies are setting the ground underneath your feet on fire.

Honestly, I don’t know why I even kept the wizard in my party. Ray of frost made ice so my martial classes would slip, and like 90% of my attempts to cast witchbolt failed. Thanks for nothing, Gale.

Disengage is another bastardized 5e rule. Right now in BG3, it’s a bonus action. It’s supposed to be an action, so you have to choose whether to move out of a melee fighter’s range safely or make an attack. That’s really making a mess out of combat, so hopefully they change that soon. It feels awful to position my melee so they’ve got everyone under control, just to have the entire enemy force walk right by them to wail on the wizard after one round.

There’s stuff that’s just straight-up broken too, which is to be expected. It was a major bummer to pick my fighting style (at level 2 for some reason?) and find that it just didn’t work. There didn’t seem to be any respec options available, so I literally threw hundreds of damage down the toilet. But that’ll get fixed!

Activating self-cast abilities can be troublesome. Stuff like dash, action surge, etc that can only ever be cast on yourself still requires you to click the ability and then click the character. I’ve misclicked a couple times and accidentally moved (& ate opportunity attacks) instead of casting action surge 😑.

The jump and disengage actions are both the same button, which can be cumbersome. I wanted to disengage from an enemy, but I guess I was a bit too far from my jump destination, because my dumb rouge walked away from the enemy, ate the opportunity attack, and then did the disengage.

The spell interactions still need some work. There are a bunch of hook horrors in one part of the game. When you engage one, it screams to alert others and bring them into combat. I was getting overwhelmed in that fight, so I tried opening with a silence scroll, which should have stopped it from screeching. But alas, it didn’t help.

The rest system is currently game-breakingly bad. Typically in DnD 5e, you have several combats between each long rest. You run low on spell slots, once-per-long-rest abilities, and hit die. But there is nothing at all that stops you from taking a long rest on demand in BG3, so you can recharge all your resources after every fight.

Hilarity & Coolness

The last companion makes an appearance right outside the druid grove, during a big battle with some goblins. I didn’t realize he was a companion until a couple days later when somebody said so on reddit, because he got horribly murdered before I could do much in that fight. Oopsies!

The shove thing is genuinely hilarious. In the underdark, there’s lots of cliffs. My character had a psychic pull power too. There was a whole area with duergar corpses who’d fallen to their deaths before I got there … and when I left, the number had expanded considerably!

Credit to Reddit user aPillowAndaSoftPlace for this hobgoblin yeet.

At one point, I came across a friendly mindflayer. That blew my mind. You can get him to explain why he’s friendly, and it’s a fascinating story with some ~implications~. He offers to help get rid of the tadpole too, but I didn’t take him up on that — my trust only goes so far 😛.

One of the most memorable moments I had was kicking down a barn door and finding an ogre and a hobgoblin just going at it. It was, uh, … yep.

Looking Ahead

The story ends before you actually make it to the city of Baldur’s Gate. That was a bit disappointing — with my new campaign starting there in a few days, I was hoping to get a good feel for it through BG3. But it’s definitely something to look forward to.

There are going to be more races, classes, and lots of subclasses added through the early access period. I went with a pretty basic sword-and-board fighter dwarf, but I think playing a goblin will be really fun. I can’t wait to see how that changes your relationship to the goblins attacking the druid grove.

I’ll definitely be doing a couple more runs through the early access story with different characters and different choices. There seemed to be a lot of doors I closed on myself by being mostly good during this run.

Geek Grind Coffee’s Goblin Gulp

In one of my DnD campaigns, our mascot is a goblin we adopted early on. He’s a big fan of coffee, so on a lark, I google image searched “goblin coffee” for something funny to put in a scheduling email.

I was surprised to find officially-licensed Pathfinder coffee offered by Geek Grind Coffee. I immediately ordered a pound of their Goblin Gulp blend. It turned up two days later.

I’ve already got coffee beans out, so I moved it into a vacuum bag and froze all but one cup’s worth of beans. The bag it arrived in is a nice collector’s item!

I brewed this with my go-to method: inverted aeropress with a little bit of salt added to the grounds. I used my metal filter instead of a paper filter so I’d get The Full Experience, oils and all.

Empty bag of Goblin Gulp & mug of brewed black coffee
Brewed Goblin Gulp coffee

It turned out really well! The mouthfeel was velvety and smooth, just like they claim in the description. I’m not sure if I’ve had another coffee with that kind of body, so it’s unique in that respect. Flavour-wise, I got lots of dark chocolate.

This was an awesome coffee and I look forward to finishing what I’ve got out now so I can have this as my morning cup. I’ll probably restock with the the 5lb bag once I’ve run out. 😁

I didn’t read much about their company — I assumed they were just a board game cafe or something — when I bought it (hash tag impulse purchase), but when I was writing this up I clicked through to their about page. They are actually a fantasy-themed coffee company that operates their own farms in Columbia:

We do not “source” our coffee as most companies do – rather we actually grow it. We harvest by hand from our own farms and the nearby farms of our friends and neighbors. We then immediately dry the coffee beans in the sun right at the mountain farms. Just hours after drying we roast the coffee in small batches then finally package the roasted in special protective packaging that assures freshness before shipping directly to your door.

story | Geek Grind Coffee

So that’s kind of cool.

Bootstrap vs. Tailwind

People occasionally get into slap-fights over the tried-and-true Bootstrap vs. newer CSS frameworks like Tailwind. I’ve worked with both — and each one has a place in the toolkit. Maybe not your individual toolkit, depending on what your job requires, but at $UNIVERSITY there was a place for both.

SUNDAY, SUNDAY, SUNDAY…

Do I need a CSS framework?

I think so! Not necessarily Bootstrap with all of its opinions on how your site should look, but you want a couple things and it doesn’t make sense to build them yourself.

The first thing you want is a CSS reset/normalization. Browsers have different default styles (lookin’ at you, form elements), and you want them to all be consistent so your changes tested in Chrome aren’t a trainwreck in Safari.

The next thing you want is a unit system. There shouldn’t be any situation in which you’re specifying dimensions/margins/padding with pixels at this point — there are too many devices and too many screen sizes.

Instead, you want relative units, but you also want your “size 5 font” to be something relatively close to your “size 5 padding”, for your own sanity. You may be able to get by with rem units, but I’ve never actually tried that, so I can’t say if everything behaves consistently.

The final thing you want in a framework is for it to deal with screen size breakpoints. I don’t want to write a bunch of CSS media queries for everything. Please give me xs-col-12 and lg-col-6 so I can get on with my life.

Of course, there’s a lot more frameworks can give you. But then we start moving into the realm of frameworks having opinions, and you need to think about what you’re picking.

Bootstrap

We all see Bootstrap’s distinctive style on websites every single day. It became ubiquitous because it’s easy to use. You can copy-and-paste the official template or any component from the docs and you’re 80% of the way done with whatever you’re doing.

As an Enterprise Application Developer, having a pile of ready-made components is a boon. You don’t necessarily care about your branding in the Enterprise — maybe it’s internal software, or you have captive customers — so a logo and changing the primary brand colour covers your needs.

You’ve then got access to the 24 pre-designed Bootstrap components. You do not need to think about web design very much. All your time can be spent worrying about implementing your app and not “hmmm, fuck, the left padding on my card is off by 3px“.

Bootstrap has an almost-invisible feature: all of the components are made with accessibility in mind. This isn’t something a lot of developers think about at the get-go, but by using Bootstrap, you’re getting 80% of the work right out of the box. When somebody does say “well what about screen readers” at the end of a project, fixing the Bad Part of your app is can be achieved in a sprint instead of requiring a major re-engineering effort.

As a developer, you can be on web-design-auto-pilot with Bootstrap. It’s a huge time-saver. It’s particularly valuable if you’re hiring folks out of those coding bootcamps — they may not have spent long on CSS, so “here’s copy-and-paste components” keeps them moving right along.

I know all us old folks are like, “hah whatever CSS it isn’t that hard“, but it is a huge topic with a lot of nuance to understand. The IE era being over doesn’t automatically make CSS simple.

Of course, there are downsides. Bootstrap still depends on jQuery, so that’s a 30kb asset that you might use for one dropdown. In the world of Enterprise Software, this might not be a big deal.

I’ve been using more Vue widgets; having Vue + jQuery loaded feels unnecessary, and there’s a temptation for developers to reach for jQuery (since it’s already there). This entrenches it in your app, when you might not wanna do that. Bootstrap v5 will drop the jQuery dependency, so there’s an opportunity to shave some page load time off coming soon.

You might catch flak when your site looks like every other Bootstrap site. This is a totally fair criticism, and a result of Bootstrap being so opinionated that it has control over 95% of your website’s design.

If “looking like Bootstrap” is a problem for your site, do not try to customize Bootstrap’s components. Adjust the variables all day long — some new colours and different corners go a long way — but Bootstrap’s opinions are its strength. Once you try to fundamentally change the look of a card, you’ve left the happy path and are deep in the woods. It’d probably be better to pick a different framework at this point.

Tailwind

Tailwind stands in stark contrast to Bootstrap: it’s a utility framework. There’s no .card class for a div that gives you an accessible pre-designed card — you’ve gotta design that yourself.

I think the easiest way to explain Tailwind is an example. From the Tailwind docs:

This feels a lot like writing in-line style="width: 100%'" attributes on every element. That is essentially what Tailwind is, but you’re using the utility classes instead of style tags, so you get the responsive stuff and a unit system. Tailwind comes with an adjustable colour palette too, so all of the utilities feel very consistent and logical.

If you’re staring at a blank web page and you want to build your app, Tailwind might seem daunting. It’s on you to design every single aspect of your pages. The framework is only going to help you insomuch as it keeps your size 1 padding relative to your size 2 padding.

You, the developer, will need a strong command of CSS to use Tailwind.

Now I know what you’re thinking, “this is an atrocity, what a horrible mess!” and you’re right, it’s kind of ugly. In fact it’s just about impossible to think this is a good idea the first time you see it — you have to actually try it.

Tailwind Documentation: Utility First

If you know what you want your page to look like, Tailwind will get you there, because there are no wrong opinions baked-in to it that you’ve gotta fight.

While I mostly used Bootstrap at $UNIVERSITY for the consistency/ease, our fundraising group had their own marketing team and they provided us with bespoke designs. They knew having a button be 3px to the left resulted in an additional 0.25% of revenue, and they didn’t care that Bootstrap wanted the button to be 3px to the right instead — they needed it their way.

In that situation, having Tailwind provide me with consistent units and otherwise getting out of my way is exactly what I need. A CSS framework’s opinions are never going to match the marketing team’s opinions, so being “close to the metal” (so to speak) with CSS is perfect.

Quarantine Omakase at Kyōten

Chicago omakase restaurant Kyōten is doing private dining right now, so you get the whole place to yourself. Having considerable events to catch up on celebrating, we decided to go for it, being the safest dining-out option you can find.

When you do omakase, you can usually talk to the chef. I’ve always felt bad distracting them during service, since there’s a bunch of other folks there waiting to. This offered a unique opportunity to chat without any guilt!

Chef Otto Phan told us about how he got started with a sushi truck (!) in Texas, before deciding he wanted to move to the big city and ended up in Chicago. Sous chef Jose made occasional appearances from the kitchen, much to our delight — he had picked the playlist and we were into it.

We arrived something like half an hour early. Maître d’ Emily hooked us up with some highballs in the lobby while we waited for them to finish getting ready inside.

I didn’t take notes as I went unfortunately, so I don’t have my tasting notes for every item. I neglected to take a picture of the dish between the beef & tamato: some delicious eel.

The uni used was unusual. It’s usually arrayed in a big wooden box; Kyōten’s came in small containers packed in salt water. It seemed richer than the stuff I’m used to, but that may have been because it was topped in a sauce made from uni.

And speaking of sauces: the nodogoro. Who would have thought shrimp brains could be so delicious? It sounded like a pain in the ass to harvest; chef played it off like it was as easy as sucking a crawfish head (which I don’t usually do, but…maybe I will from now on?).

I don’t remember what type of caviar we had, but that wasn’t the most interesting part of that course — the fish it was served atop was. I think it was tilefish. When the sous chef brought it out of the kitchen, I thought it had a panko topping or something. Turns out, tilefish scales behave like popcorn when heated. So that was cool.

The toki shirazu was cool. It translates as a fish that “knows not time”. This is an individual salmon that doesn’t care about the changing of the seasons, so it never heads up a river to spawn. The result is visible in the flesh: that piece of salmon lacks the typical thick white bands of fat.

The rice requires mention. They use a type of rice I’ve never encountered before. From their website:

Shari (sushi rice) plays a central role in our sushi philosophy.  Kyōten uses a very special and exclusive varietal of rice from Japan called Inochi no Ichi, the first (and currently only) restaurant in the US to use this paricular grain.  Our shari is boldly seasoned with the intense taste of aged red vinegar.  Different rice recipes are used so that they pair fittingly with different kinds of fish. 

Kyōten Website About Page, Retrieved 2020-08-13

I did a drink pairing. Chef had chosen eight sakes & wines to go with the meal. Once again, I regret not taking notes as I went, but I do remember a couple notable things!

The lambrusco, a lightly sparkling red, was something new to me. The Ancient Treasure served with dessert was like a dark chocolate. I’m not all that well-versed in sake, but that’s not something I’d seen in a sake before.

The Tokaji was a real treat, mostly because I didn’t know this was a real thing. If you are familiar with The Golden Compass: the Master of Jordan College poisoned the tokay (another spelling of tokaji) intended for Lord Asriel in the opening scene. This was very much a dessert wine, but it wasn’t as overpowering and heavy as one of my other favorites with a similar taste.

The omakase & drink pairing menus

As with many high-end restaurants, Kyōten gave us a box to take home and enjoy for breakfast the next morning. It was a mystery box. When I took the ribbon off and opened it on Monday morning, it was revealed to be a yachae kimbap — a Korean vegetarian sushi roll, made with their inochi no ichi rice, some pickled vegetables, and tamago. A splendid breakfast!

Yachae Kimbap

The UI Trap in Microsoft Teams

I have moved orgs and no longer live in Microsoft’s Slack competitor, Teams. So before I forget the frustration, I wanted to write up the severe, crippling flaw in Teams’ UI.

Here’s a screenshot. Note the leftmost sidebar: a “chat” tab, and then a separate “teams” tab:

Ignore the un-compacted chat layout. After a few months, you get used to it 🤷

“Teams” is the chatroom function, whereas “chat” are where your DMs are. If you’re in one tab, there’s not a great way to see what’s happening in the other. You have the “Activity” section too, but that’s another area that swaps you out of chat entirely, so it doesn’t really help.

This causes a huge problem — people live in the Chat tab, or they live in the Teams tab. Over time, the fact that people only wanted to live in one meant they’d stay in the most flexible tab: chat.

This degraded the entire product for me. I tried really hard to get people to use Teams so folks could follow the discussions they were interested in. In one group, I was successful — but everyone else ended up DMing me or setting up small group chats.

The DMs hurt information availability, since you need to be invited to a group chat, and the search functionality in DMs isn’t as good as in the team chat rooms.