CH

September 26, 2016

Socialist Trolley Problem

Filed under: philosophy — Benjamin Vulpes @ 11:30 p.m.

You stand by a switch that can send a trolley careening down one of two tracks. You can't stop the trolley and you can't affect what is down the track in any way other than to throw the switch.

There are 100 people tied to track A, and 99 people tied to track B. None can escape. The switch is currently set so that the train will fly down track A, killing everyone tied to that track.

But!

Some of the people are straddling tracks A and B, and you have no idea whether your trolley will amputate their legs or decapitate them, or how many will suffer which injuries. Furthermore, there are unknowable external effects to both throwing the switch and not throwing the switch, effects whose scale of lethality may dwarf the number of people tied to both tracks put together (both in integer deaths and aggregate micromorts). Additionally, you've never even seen these people, you just read about their existence and the risks to it on Reddit.

Do you throw the switch?

September 25, 2016

A Robust, Testable (and tested), Reentrant Timer in Java and Clojure

Filed under: clojure, java, software development — Benjamin Vulpes @ 6:30 p.m.

I do most of my for-pay web work in Clojure. It's a Lisp, that the popularity of JVM-hosted languages has made acceptable in both Enterpriselandia and Startuplandia1, and so wasn't the worst choice in the world for this particular kid (already entirely competent with the kazoos of Python and Java) to build a new base of competence (and at the time I decided to develop more than just base competence, I hoped it'd yield some marketability as well. Marketability it might have had, but not for the product I was marketing) in. Java, being a product of the web generation ("hey, we got them using garbage collection, whaddaya want?!") for the web generation, comes with a...large set of tools to handle the variously surprising and predictable braindamage the practicing hacker encounters in daily webshittery. Clojure provides a baseline-acceptable set of asbestos gloves for working with the JVM2 that I've wielded to great effect building postback webapps, and APIs for single-page JS applications.

Today I will share with you a smattering of non-production code, demonstrating testability of an important subsystem that every webapp develops at some point: the scheduled job. Find attached a tested, and further testable system for scheduling events, written in plain old Java, and called from Clojure (this is excellent study material for novice Clojurians wrapping their heads around interop with the host platform). The code and its tests assume that the timer and its testable implementation are swappable in your system (or to use the self-aggrandizing software industry lingo, that you thought far enough ahead when writing whatever you're building that it provides for Dependency Injection).

A Java interface that both the timer and its testable version will implement:

public interface Timer {

    public interface TimerCallback {
        public void execute();
    }

    UUID schedule(TimerCallback callback, Date date);
    void cancel(UUID uuid);
}

The implementation:

public class ConcreteTimer implements Timer {

    private HashMap timers;

    class ConcreteTimerTask extends TimerTask {

        TimerCallback callback;

        public ConcreteTimerTask(TimerCallback callback) {
            this.callback = callback;
        }

        public void run() {
            callback.execute();
        }
    }

    public ConcreteTimer() {
        this.timers = new HashMap<>();
    }

    public UUID schedule(TimerCallback callback, Date date) {
        ConcreteTimerTask task = new ConcreteTimerTask(callback);
        Timer timer = new Timer();
        UUID uuid = UUID.randomUUID();
        timer.schedule(task, date);
        timers.put(uuid, timer);
        return uuid;
    }

    public Date getDate() {
        return new Date();
    }

    public HashMap getTimers(){
        return timers;
    }

    public void cancel(UUID uuid) {
        Timer timer = timers.get(uuid);
        timers.remove(uuid);
        if (timer != null) {
            timer.cancel();
        }
    }
}

The testable system:

public class MockTimer implements Timer {

    public class MockTimerTask extends TimerTask {

        TimerCallback callback;

        public MockTimerTask(TimerCallback callback) {
            this.callback = callback;
        }

        public void run() {
            callback.execute();
        }

    }

    public class MockTimerObject {
        public UUID uuid;
        public MockTimerTask task;
        public Date date;

        public MockTimerObject(UUID uuid, MockTimerTask task, Date date) {
            this.uuid = uuid;
            this.task = task;
            this.date = date;
        }

        public Date getDate() {
            return this.date;
        }
    }

    private List timers;
    private Date mockDate;

    public MockTimer(long init_millis) {
        this.timers = new ArrayList();
        this.mockDate = new Date(init_millis);
    }

    public Date getDate() {
        return mockDate;
    }

    public List getTimers() {
        return timers;
    }

    public UUID schedule(TimerCallback callback, Date date) {
        MockTimerTask task = new MockTimerTask(callback);
        UUID uuid = UUID.randomUUID();
        timers.add(new MockTimerObject(uuid, task, date));
        return uuid;
    }

    public void cancel(UUID uuid) {
        timers.removeIf((MockTimerObject m) -> m.uuid.equals(uuid));
    }

    public void advance(long millis) {
        timers.sort((o1, o2) -> o1.getDate().compareTo(o2.getDate()));
        if (timers.size() > 0) {
            MockTimerObject callback = timers.remove(0);
            if (callback.getDate().getTime() > (mockDate.getTime() + millis)) {
                mockDate = new Date(mockDate.getTime() + millis);
                timers.add(callback);
                return;
            } else if (callback.getDate().getTime() <= (mockDate.getTime() + millis)) {
                Date oldDate = mockDate;
                long target = mockDate.getTime() + millis;
                mockDate = callback.getDate();
                callback.task.run();
                advance(target - callback.getDate().getTime());
                return;
            }
        } else {
            mockDate = new Date(mockDate.getTime() + millis);
        }
    }
}

Calling it from Clojure:

(defn instantiate-callback [callback]
  (reify Timer$TimerCallback
    (execute [this] (callback))))

(deftest can-advance-mock-timer
  (let [then-millis (long 1e6)
        mock-timer (MockTimer. (long 0))]
    (.advance mock-timer then-millis)
    (is (= (Date. then-millis) (.getDate mock-timer)))))

(deftest mock-timer-runs-tasks
  (let [when (Date. (long 1e6))
        mock-timer (MockTimer. (long 0))
        callback-fn (test-utils/dummy-fn)
        timer-callback (instantiate-callback #(callback-fn 1))]
    (.schedule mock-timer timer-callback when)
    (.advance mock-timer (long (+ 1 1e6) ))
    (is (= '((1)) (callback-fn)))))

(deftest mock-timer-runs-tasks-in-order
  (let [time-1 (long 1e6)
        time-2 (long 1e7)
        mock-timer (MockTimer. (long 0))
        callback-fn (test-utils/dummy-fn)
        callback-1 (instantiate-callback #(callback-fn 1))
        callback-2 (instantiate-callback #(callback-fn 2))]
    (.schedule mock-timer callback-2 (Date. time-2))
    (.schedule mock-timer callback-1 (Date. time-1))
    (.advance mock-timer time-2)
    (is (= ['(1) '(2)] (callback-fn)))))

(deftest mock-timer-works-reentrantly
  (let [time-1 (long 1)
        time-2 (long 2)
        time-3 (long 3)
        mock-timer (MockTimer. (long 0))
        callback-fn-3 (test-utils/dummy-fn)
        callback-3 (instantiate-callback
                    #(callback-fn-3 3))
        callback-2 (instantiate-callback
                    #(.schedule mock-timer callback-3 (Date. time-2)))
        callback-1 (instantiate-callback
                    #(.schedule mock-timer callback-2 (Date. time-1)))]
    (.schedule mock-timer callback-1 (Date. time-1))
    (.advance mock-timer (long 5))
    (is (= '((3)) (callback-fn-3)))))

Writing a timer system in this style blesses your entire system with a new axis of testability. You can construct your mock timer objects in test setup, pass them into (for example) functions responsible for processing HTTP requests, realizing side-effects, and then returning HTTP responses, and in your test suite assert that after a certain amount of time has elapsed, that the timers perform the jobs as designed. You can even test that reentrantly-scheduled jobs ran, and that they performed their side-effects as expected.

On the flip side, this kind of onanistic software development balloons budgets and drives teams to blow clean through their deadlines. You're probably better off just instantiating a java.util.Timer whenever you need one. Testability of complex systems is expensive, and your customers will probably never notice if the jobs don't run correctly anyways. Even if stakeholders do observe some flaws in your program, you can slow-roll them with reproduction requests ("Sorry, that's not really detailed enough. What do I do after making a new Frobulator to prevent the Frobulator Inspector from running next week?" while you labor frantically behind the scenes (manually testing everything, of course, because your team's moving too fast to write tests) to run down and fix those bugs.

  1. Enterpriselandia cares only about the IBM-ness of any given technology choice ("Nobody ever got fired for buying Microsoft!"), and the children of Startuplandia, absent of course any sort of historical perspective on software development care only about the top shiny. []
  2. It still features a few glaring warts: system startup time is so hilariously long that luminaries have bolted libraries together "...for managing the lifecycle and dependencies of software components which have runtime state", a fancy sidestep of the issue that the base REPL (your interpreter/compiler in a Lisp) takes so long to boot that folks prefer to set up and tear down running systems by hand rather than restarting the runtime; and the utter inability of the compiler to perform any sort of type checking, along with the concomittant attempts to paper over the issue: Schema, Spec, and the disingenuous notion that compile time type checking doesn't matter at all:

    While I may actually agree with Halloway on the point above from the managerial perspective, this verges on a claim that "Stakeholders don't care if drivers are working the stick or piloting an automatic". While that may be true for your VP of Marketing, I guarantee you that whichever human is responsible for controlling fleet maintenance costs does in fact give a shit, and does in fact prefer that drivers not operate the transmissions by hand. []

September 24, 2016

Portland Road Etiquette

Filed under: auto, portland, traffic, velo — Benjamin Vulpes @ 8:46 p.m.

Should you find yourself operating a motor vehicle, bicycling around my fair city, walking, or merely a passenger in someone else's fashion-item-masquerading-as-capital-equipment, understanding the local road mores brings a moderate bonus in navigation efficiency, provides cultural background to silently judge fellow denizens of the asphalt, and the context to appreciate just how bad drivers in this oversized town really are.

The world is a sad and miserable place, drivers and other road-users the saddest and most miserable of even Americans. Do your part to bring cheer and happiness to the world by surprising and delighting everyone around you by gifting them your right of way should you find yourself in the unfortunate position of having it. That the "right of way" should accrue to any one person in an interaction is a pernicious artifact of the confluence of patriarchy, capitalism, and zero-sum economics: we must all band together and take care of each other, and the best way to do this is to give people the right of way unprompted and unexpectedly.

When you consider the speed limit, know that ODOT traffic engineers simply follow Federal guidance and seek to optimize on average vehicle speed through every section of road. This bit of knowledge should convince you that the speed limit is dangerously high, and ODOT doubtless at fault for more fatalities than hormone-flooded teens, heavily intoxicated Beaverton residents attempting to get home from Dirty at 2:30, and negligent vehicular homicide, firearms, and maniacs prowling malls all put together. With that in mind, you should never ever even approach the speed limit, and if traffic conditions are anything more hazardous than a completely empty road in the middle of summer with the sun to your back, 10MPH below the speed limit is likely safer. All of the above guidance is even more relevant in the sub-30MPH regime. Don't try to extrapolate some sort of percentage below the speed limit that is safe for those situations, you'll just distract yourself with the problem, run over someone's doddering grandmother, and then how will we forestall the Trumpenreich?

You will frequently see orcs, barbarians, Californians and Washingtonians violating these rules (less frequently, you'll see Canadians driving around, but they have a sixth sense for the rules in any given place and unerringly adhere, so you'll probably never observe them actually transgressing). At first, shock will course through your veins: "Did he just turn right under a red right-pointing arrow?! Doesn't he know how dangerous that is?!". Thirty seconds later, as the adrenaline spike from watching someone else break the rules in a most dangerous fashion drains from your bloodstream, leaving you a shaken, harrowed mess, you may remember that you purchased a vehicle factory-equipped with a horn, and that the opportunity to use it fast slips from your fingers. Think carefully now about honking: did the Californian commit a bona fide infraction? Could you perhaps explain his or her actions to your passengers as born of ignorance? Possibly your antagonist is simply having a bad day, and per the Universalist mandate, you should forgive them their sins because lord only knows what mistakes you made while driving today, for which other drivers forgave you, all unwitting.

If, after all of this searching to understand your and your counterparty's places in the cosmos of transit, your identity politics permit you to take the exceptionally hostile act of honking at another human being, you may lay on the horn for no longer than one and a half seconds, and you may only emit one blast like this. Remember, you are no New Yorker, relying on the primitive single-bit horn to communicate such varied information as "the light has turned green and you should probably move your ass at this point" or "hey dipshit parallel parking on Burnside during rush hour is one of the more spectacularly stupid things I've seen on my commute today", or a Cairo-born cabbie still under the delusion that the horn is a useful way to communicate that he's in your blind spot ("In this country we are civilized, sir, and check our blind spots before actuating our turn signals! What mean you by these five tenth-second beeps?!").

Under no conditions may you lay into the horn to advise people around you that some Bad Shit is about to happen. Mind your own business.

Rush hour, to return to a previously tangentially touched-upon topic, is the one time when you are allowed to become frustrated by the speed of life in Portland. At all other times, you have no business zooming around at (or above!) the speed limit. This is a small town, zhir or mrdame, and the roads not congested. Moreover, you are in no way more important than anyone else, and so your feelings of frustration at the time it's taking you to get your wife and about-to-be-born child to the hospital are entirely unfounded, unjustified, and downright elitest (you scum). Unfortunately, during rush hour, everyone else is on the road trying to get home at precisely the same pathetic crawl as yourself, and so you should really just put those feelings of put-out-ed-ness down and turn the dial over to NPR to catch the news. Besides, you get stuck in this morass every day anyways, why are you still getting bent out of shape?

Please use every bike lane for anything that comes to mind! Should you need to unload packages, the bike lane is a fantastic place to put your car while you run up and down the stairs of your unreinforced masonry building whose owner wisely decommissioned the elevator in advance of ADA regulations hitting the books to avoid having to maintain it and service handicapped tenants. Should you need to turn right (or left in some parts of town!), make sure that you rush up to your corner, pull into the bike lane, and then watch your rear view mirror until the bicyclists safely navigate around you on the side to which you are not turning, and then continue driving. This ensures that you get to the corner as quickly as possible, that you demonstrate great care for others' safety on the road, and that the greatest amount of time and space is wasted. This will feel natural for your first three years in Portland, then for another four years you'll be horrified at the sight, and then some three years later you'll stop giving a shit as you achieve traffic mastery and glide through the world quickly, confidently, and elegantly without attracting even so much as a single side-eye.

If a car a block in front of you is stopped in your lane, drive up behind them and at the last possible moment, change lanes (remembering to inspect your blind spot!) and swerve around it. This will maximize your chances of running a hapless pedestrian over. If you're lucky, you'll hit one of the children of the elite, and the rest of Portland will cheer. You should seek to swerve at just under the lethal-to-strike-pedestrians-at speed so as to maximize the healthcare costs that her family will have to bear. Do your part to reduce income inequality! Rich people don't have to buy health insurance like you and me; they have a bevy of accountants instead.

Queue aggressively. If you know that these three lanes neck down to two some four miles down the road, you must not drive in the lane that is closing from the moment you get on the highway until the moment that lane closes. Maximizing the number of cars packed onto the highway isn't your concern: your concern is to be as polite as possible, and to avoid the hassle of merging when the road actually applies pressure to do so. Only self-important assholes in Mercedes, dildos careening about in Corvettes and penis-cases on unmuffled sport bikes are so selfish as to use the empty lane on the right to pass the polite, calm, nice, right-thinking real Portland drivers who queue up in advance and voluntarily burn their own precious hours to serve the greater good.

Finally, plan your trips such that you always need to turn left across the major two-lane streets in town like Burnside, MLK and Sandy. That the two lanes of oncoming traffic are nearly fully-subscribed, that the minimum amount of time you'll have to wait for an opening is over three minutes, and that you're delaying an entire regiment of cars behind you should bother you not one whit, for you are following convention and turning left across major roads as instructed.

Should you find yourself stuck behind someone turning left like this, you are strictly forbidden from honking. That would be rude.

Bicyclists, I have guidance for you as well, but I shall keep it brief, as my child has woken up and I would like to play with him.

Firstly: thou shalt ride up Hawthorne, one of the Southeast's busiest streets without a bike lane taking up a full vehicle lane. Most riders will prefer the right lane, but I award the most points for taking up the left lane: you'll never know when a bus will be using the entire right lane to pick up and drop off, and you want to maximize the inconvenience delivered to drivers in your vicinity. Besides, per Oregon 814.430(2)(c) this is fine! There are caveats of course, but you can always feign ignorance and smash someone's windshield with your bike lock if they get in your face. In general, you should never ride through quiet, safe, low-traffic neighborhoods or along designated bike routes with no stop signs and cars routinely diverted off if you can instead make a nuisance of yourself to drivers.

Pedestrians, you're mostly all conversant with how to best operate your butts around town, but I still have a few pointers for novices.

Approach corners striding aggressively (remember, "every corner is a crosswalk", and all other traffic is required to stop for you. Even on MLK and Grand!), wait for cars to arrive at the conclusion that you intend to cross and stop for your transit across the road, and then abruptly stop to pull your phone out as though you've just received the most important text. This signals to the drivers that you don't actually intend to cross, and they can now burn a bunch of gasoline to re-energize the vehicles they just stopped for you. Do your part to make car ownership expensive and an indicator of elite status.

Remember to never jaywalk. If the walk sign is red but there are no cars, you should linger on the corner for as long as possible to get the opportunity to cross while some driver is waiting to turn left until you pass through the crosswalk. If you find yourself in the middle of a block and want to cross, walk instead to the nearest corner, wait for a car to make nervous with your presence, and then stroll casually in the right direction. Bonus points if Google Maps suddenly routes you in the opposite direction and you can turn around without checking your blind spot or where the cars around you are and want to be.

Be safe out there!

September 19, 2016

The Hilarious Unprofitability of Uber

Filed under: capital equipment, philosophy, shartups, software development — Benjamin Vulpes @ 2:29 a.m.

As far as I can tell, Uber and friends have spent an extraordinary amount of money demonstrating that mobile devices are a phenomenal sales channel for traditional businesses directly into millenial pockets. Oh, and to illuminate incontrovertibly Silicon Valley's downright perverse aversion to operating capital equipment.

Uber sets prices unilaterally on both the demand and supply sides of the market for just-in-time butt delivery, controls 'fleet' eligibility criteria, suffers none of the friction of operating its own capital equipment, doesn't eat any depreciation charges, will finance chumps"driver partners" lease of the cars, and can even arrange for operators to rent cars from Enterprise and yet they still cannot make any money. What, as we say, dat? Could Uber be competing to own the vertical and horizontal in a space and failing to bite off an element of the business model that profitability is predicated on the ownership of? Fans of business-gore, like myself, live for moments of fail like this.

Controlling both the cost of goods sold and the price at which those goods are sold ranks right up there with "not letting the employees walk out with your cash" in terms of business fundamentals, and while some degree of authority over these two knobs is important for running a business, normally they're set by a combination of corporate authority and market dynamics, eg the price of similar goods and services, and suppliers ongoing pricing exercises with their goods and services. Uber suffers none of these ugly real-world interferences in their pricing: customers simply ask to be picked up at a place and dropped off at another place, the app does so, and then at the end conveys a price. Pricing, as far as the customer is concerned, is not merely opaque but actually unknowable until services have been rendered in full1, and as (Uber claims...) fares go mostly directly into driver pockets this sets the payout price as well. Uber will gladly provide an estimate, and many-a-website claims to have deep insight into the fee structure, but the fact remains that they slam the numbers around at will, nominally in service of sliding around on the price elasticity manifold.

Intriguingly, the subsidies that apparently account for a large fraction of the company's losses don't even show up in markedly lower prices than traditional cab companies, at least in my entirely un-statistical sampling of a few trips up and down Sandy Boulevard this summer in various traffic situations. Given the whole "disrupt disrupt disrupt" thesis that the application of software can2 make order of magnitude improvements in profitability, how is it that Uber is neither profitable, nor do they deliver services for a tenth what everyone else charges?

That's not all, though! Uber is also willing to help schmucks3 finance the very vehicles they're going to depreciate shuttling app users around. Cursory research indicates interest rates in excess of 20%, so almost definitionally Uber appears intent on leasing vehicles to the least responsible folks around4. Get this though: the billion-dollar line of credit for leasing vehicles to Uber operators is not intended to be a profit center. Some short time after I found that gem out, I began to wonder if they intend to make money or if the whole show is an elaborate way to burn a pile of money to offset wins from other portfolio companies while keeping friends and family employed.

Operating capital equipment is complicated, and Silicon Valley (as demonstrated through Uber's behavior) hates it. The challenge may be stated as: "operate everything for as long as possible, constantly balancing maintenance costs against replacement costs". Cars, unfortunately for the consumers and Uber's vehicle drivers, are not generally designed as capital equipment, but as fashion items. My environmentalist friends love to lament the forced waste of the fashion and technology industries, and how planned obsolescence and ever-changing fashions ensure that American consumers must routinely upgrade both their computers and their clothing to continue deploying the impression of being au courant5 and for the manufacturers to keep on with the making-of-money, but their eyes slide right over the same exact dynamics in the consumer automobile industry. For one example of the difference between designing capital equipment for the road and designing consumer equipment for the road, consider that a consumer car that's been driven for 100,000 miles is worth veeeery little (perhaps a tenth of its MSRP), and a Freightliner Cascadia with 600,000 miles on it goes for just under a quarter of MSRP. There are hints that the Tesla Model T can hit 300,000 miles without much wear and tear, but they're entirely anecdotal and its "refueling technology" renders it entirely useless for the task of JIT butt-schleppment.

Perhaps not even bothering to manage consumer-grade vehicles operated on busted roads by the wonderful people who have the time and inclination in their lives to drive vehicles around to make ends meet is the only way that Uber even makes sense as a business model. On the other hand, grow up, buy real equipment, hire and train labor, and actually run a business instead of a pile of servers.

Just an idea.

  1. This is amusingly similar to the market practice of many freelance software development organizations and individuals, wherein the potential customer is told that a thing is "So easy! Right up our alley! We do this all the time! You'll have it in 2 weeks!", and then two months and sixty thousand dollars later, the customer realizes they've been fleeced by con artists well-practiced in the art of delivering just enough to keep the mark convinced that delivery in full is just around the corner of another ten grand. I attribute a large part of my abject failure to stuff cubicles with commodity labor and churn out software all day long to how willing I am to tell people that there's no way my or any other team can shit out a responsive mobile banking "web app" with all those features in six weeks, that that other feature is a piece of braindamage your sales team only determined that it wanted after a potential customer (no doubt one of the smaller who won't even buy your system in the end after jerking you around for months during the sales cycle) casually asked if your thing did whatever, and that shit dog are we even going to talk about how much friction there's going to be collaborating with a 12-hour offset team that owns the server-side? So yeah let's just say four months and a half million dollars, and we still won't have bitten off the dumb shit at the bottom at that point. Hey, buddy, did we kill that deal yet? []
  2. Computronium, particularly in the context of user-interface development and the current environment of Apple-flavored C, Google-flavored Java and the traditional hell of HTML CSS and JS all executed together to make buttons happen in browsers, is dangerous shit, not to be touched by children or individuals not trained to shoot creeping complexity in the face at first sight. If a business operator isn't careful, designers and developers can waste untellable fortunes building egotronic affordances that don't make any sense either from the user's perspective, or the perspective of designing within the UI toolkit's paradigm to reduce complexity, and that will never feel right anyways because it disregards entirely how UI widgetry is built for the target platform (oh and I'm just talking about pathologies I've seen in working for one platform. Shit gets even more unruly and out of hand if people try to make sensible UI's for wildly divergent base operating systems. As one example of sanity, when one ports Civ from DOS to Mac, it comes pre-baked with its own menu system, so porters don't have to struggle with "how do I best express this application's basic thesis to Mac users when it was written for Windows?", instead the app carries all of its own UI widgetry along with it. This is a downright sensible approach, because it neatly carves off the entire discussion of how best to design for $OPERATING_SYSTEM's inane conceits. It's also a very tough sale, except if you import the cost of writing your UI layer in the browser hell, in which case nobody will mind that it's nonsensical and impossible to maintain.). A few quarters of this kind of behavior is guaranteed to drain budgets and emit entirely unmaintainable code. []
  3. "Why do you keep insulting Uber drivers, Benjamin? They're nice people just like you!" Because if you are pulling less than thirty dollars an hour to both be busy and cover the depreciation of your vehicle, you are failing to price approximately the whole world into your cost basis. Keep in mind that Uber imposes pretty strict "must be newer than" requirements on vehicles in their 'fleet', which entirely rules out operating the capital equipment after it's depreciated off the books, a topic worth thinking about in some small amount of detail. []
  4. Yes, yes. "Credit scores aren't people, Benjamin!" Sure, whatever. While some people with bad credit may be victims of the paint-by-numbers governance of the US population, the vast majority are actually bad credit risks. If the king demands that you show up for church every Sunday or be ineligible for crown subsidies, your options are to a) do it, b) kill the king and take his money and c) not show up. Know, though, that the latter two options aren't going to set you up for good loan terms. Getting upset at the insanity of your local power structure and opting out means you opt out. Just because nearly-anonymous-credit-approval-by-the-numbers is stupid doesn't mean that one may ignore it without repercussions. []
  5. As of approximately a year and a half ago, I cooled my wardrobe by a few hundred K to contain a formal outfit and an informal outfit. The formal outfit is a black suit, and the informal outfit consists of a particular brand of black V-neck t-shirt that I've already somehow managed to get differently-fitting versions of despite buying the same brand, same model every time, black Levi 511s, and a pair of black ankle-height shoes (in the spirit of maximizing the clothing's lifespan, there's also an outfit for the 10 miles of "vigorous bicycling" (to quote one calorie-tracking app of no particular note) between the office and the house, but that's cobbled together and not holistically designed. It's for sweating in, not for coordinating with the rest of the family.). Minimizing cognitive overhead is a lifestyle optimization. Some days, I'm tempted to place an order for a pallet of MREs and live off of that at the office. It'd be not just a reduction in the cost of figuring out where to lunch (which is always complicated by deferring the eating until my blood glucose levels drop below the 'useful human' level), but also vastly cheaper than eating lunch in downtown Portland! I'm milking this cheap-ass-motherfucker schtick to great effect in many aspects of my life. Highly recommended, especially if you're the hardworking-yet-broke, but-somehow-stupid-enough-to-be-family-having type like myself. []

September 15, 2016

Enlightened Self Interest and Dishwashing Optimizations

Filed under: la vida pobre, philosophy — Benjamin Vulpes @ 9:36 p.m.

I wash the dishes in my house. The chore suits my domestic arrangement well, as I vastly prefer having my food cooked to cooking it myself, and I can typically knock out a day's worth of dishes in under twenty minutes. It's a valuable "active meditation" for me, much like yoga. The difference being that the forty minute bike ride into and out of the city each day has completely eaten up my allocated time for exercise, I like my yoga sessions to go for something on the order of an hour and a half, and just cannot summon the fucks to do yoga regularly anymore.

Anyways, the dishes. On those infrequent events where my little family ventures to a friend's house for dinner (and even less frequently, stay long enough past the child's bedtime to observe the friends' dishwashing practice), and those more frequent events where the friends congregate in our little cottage ("Baby it's a cottage, not a hovel! An adorable cottage, a ten minute walk from the river!") , I like to note the various processes my friends use to do dishes and their various strengths and weaknesses. Since I do this particular chore on an ironclad schedule of every fucking day, I have spent a fair amount of cycles on optimizing the work, and I'm going to share some of the optimizations I've found with you! Aren't you lucky.

A few principles that drive my dish-cleaning practice:

  • Minimize dirty dish lifetime on usable surfaces
  • Keep the dishwasher empty and ready for loading at all times
  • Use the machine to do as much work as possible
  • Minimize time spent washing dishes
  • Have the right tools
  • Optimize hardware choices for dish-wash-ability

Because I am a tightfisted jew, I've emplaced my family in a tiny cottage with a tiny kitchen. When shopping around for the new place, I was dead-set on finding a house with a garbage disposal, or "garburator" as our sorry ("Sorry!") neighbors to the North call them, but eventually relented and traded the garburator for a hood over the stove, as: cleaning dishes is simply messy work, and if I can ease the cook's job on the smoke side of things, well shit who knows what marvelous new dishes she'll crank out, thereby improving my life rather more dramatically than having the garbage disposal would. The other factor that shifted out from underneath my original list of "must-haves" was that we eventually elected to live waaaay out in Milwaukie (technically an unincorporated part of Oak Grove, but this digression threatens to spiral out of control into real-estate insider baseball if I keep on in this vein), which unlike Portland and in the same fashion as other civilized places does garbage pickup once per week and so disposing of food waste into the trash can.

"What?!" I hear you ask, "Portland does garbage pickup at a frequency of less than once per week?!" Why of course, friend! In a laudable (but not lauded!) attempt to reduce the amount of landfill mass the city produces, some glorious socialist of mayorhood past determined that henceforth the city shall provide tiny little compost buckets, which shall live on citizens' counters to receive disposition of food waste. The state decreed that citizens shall empty those (now particularly stinky, on account of only having warm decomposing food matter in them) buckets into the yard debris bins which are collected weekly, and that collection of refuse sent to an industrial composter. The incentive the governors fell upon to get people actually using their harebrained scheme dovetailed perfectly with their goals to reduce landfill: drop garbage pickup from once per week to every other week.

The whole charade is an excellent example of how the slow-motion socialist takeover has robbed my generation of even knowing that they've been robbed. Not only have the services delivered been halved, but it's sold on the premises of "composting is better than landfill" and "we've reduced our landfill flux by thus and such amount (by halving services)". No shit, I could more than halve the carbon output of the metro area, just by taking away the cars of the bottom 50% of earners, and before you go off on me for "omfg but that's precisely regressive taxation!!" consider that the cost of garbage takeaway is a vanishing fraction of household budget for the wealthy, and for the impoverished Greshamite a thing to consider very carefully in the monthly cashflow allocation. The wealthy can simply spend another impossible-to-see-from-orbit fraction of their wealth to have the larger garbage cans delivered and emptied, while the poor (and barely-middle-class like myself) had to decide if we're going to spring for the larger can or simply live with fewer pickups.

The tiny kitchen in my hovcottage basically demands cleared counters for any sort of serious cooking project—there's barely room to turn around, much less spare square inches for dirty dishes. To that end, an important principle of dish-doing (and in fact living a sanitary, tidy, well-groomed life) is to keep the counters clear for use. So: whenever I find myself at loose ends for ten minutes (eg in the middle of a conversation, taking an interruption while the lady puts the child to sleep), the first task I turn to is to push more dishes through the cleaning pipeline, ideally all the way into the dishwasher.

On the topic of the dishwasher, there are two mandates from heaven regarding its use: 1) keep the dishwasher empty, and 2) use it as heavily as possible.

The first is a hard efficiency requirement, and a prerequisite to making progress on dishes at the drop of a hat, with a minimal amount of faffing about. If the whole effort is judged not by dishes returned to the cabinets (which it won't be, "out of sight, out of mind" and all that), but rather on the time between the transition into the dirty state and the transition off the counter, whether that be into the dishwasher or back into the cabinet, then optimizing for that case demands that one keep the dishwasher unloaded or running at all times.

The second mandate, "use the dishwasher as heavily as possible" is significantly more floppy and subject to interpretation. At the highest level, it means "wash nothing by hand that the machine can wash for you". In practice it must be construed situationally: if the thing is 1/3 full and the person clearing the dish pipeline doesn't anticipate more loads coming through, run that fucker and empty it! Odds are that the next meal is going to blow clean through that remaining 2/3rds capacity leaving one with dishes to clean by hand. Number and size of pots and pans to clean also affects optimal dishwasher use: you don't want to waste precious rackspace on a single giant pot (which may well interfere with your top rack spray arm as well!), so clean that shit by hand!

Minimizing time spent doing dishes is the fundamental cost function to apply. A large pot takes approximately as much time to clean thoroughly by hand (give or take a baked on sauce) as 3-4 plates, if you have your tooling well dialed. Therefore, if you can stick 6 plates into the space that a pot would otherwise occupy, you should clean the pot by hand and wash the plates in the dishwasher.

As far as tools go, the selection I've found most useful consists of a flexible ceramic scraper, a chain mail scrubber, soap and sponges, and scouring pads. One pass with a putty scraper should be adequate to get more-or-less anything off the surface, a brisk scrubbing with a chain mail scrubber (strive to purchase capital equipment that will last, it'll save you the headache and opex inherent in depending on consumable tools) should remove the small bits impractical to pop off with the scraper, and a final pass with a sponge and generous helping of soap will clean the surface and (if you're doing it right) get the rest of the bits off. A scouring pad is a useful addition to remove the most persistent films and baked-on greases.

Picking dishes that can survive heat and water and soap is another optimization route. For me, this means regular conversations with The Procurement Department about the unsuitability of various household items for cleaning in the dishwasher, and the unconscionable impact such devices have on the time it takes to "do the dishes". EVERYTHING MUST GO IN THE DISHWASHER AND THAT MUST BE FINE. At least until I hire a dishwasher for my house.

Until such a day as the children are large enough to do the dishes themselves (at to my stringent requirements at that) and I can deploy my human assets against the problem, I will continue to lust after commercial dishwashers like the Noble Warewashing UH30-E. Dishwasher duty cycle is the largest single component in my dish-processing flow, and if I could get that down to a 2 minute run instead of a 40 minute run (granted, the dishwasher in this rental is old and slow, but I've never used a consumer dishwasher that didn't take at least 30 minutes per large, moderately-soiled load), holy shit the time I'd save.

At the end of the day, I try to treat dishwashing as any other industrial process. There is capital equipment involved, and it should be operating more-or-less continually. There are resources (counter space, primarily in my case), for which contention must be minimized. I want to keep the high-quality meals coming out of the kitchen, and so I do my damnedest to set my dearest chef up so that her job in making us food is as easy as my job in loading the dishes—everything the lady needs to make me happy should be ready for her use.

Enlightened self interest! An important princple in the humble domestic sphere.

Older Posts »

---