Wednesday, March 6, 2019

Choron: Distributing Housework with a Fair Market Economy

When I was in college, some friends and I thought: Hey, wouldn't it be neat to encourage a fair distribution of housework using a market-based auction system? Capitalism is pretty great at scale, so why not try it at home?

Turns out: we were totally right, and it was awesome.

We wrote an app called Choron. It's like a utilon is the unit of utility, or a hedon is the unit of hedonism: a choron is the unit of chores.

It's written in Ruby on Rails. It ran on our local area network and wasn't exposed to the Internet, because we definitely didn't trust our own ability to secure it. We configured our router so that when you were on the network, "http://choron/" would redirect to the server, which ran on an old laptop my mom gave me sitting in our closet. The server went down once because someone closed the laptop's lid.

We wrote our MVP in one frantic weekend of staying up late and doing Rails tutorials. I'd never written Ruby before, but it was pretty simple to pick up. Rails was magic. My roommate and co-founder (and now, spouse) hated how magic it was. I found that the trick to writing Rails was to just pretend everything was fine and would work the way you expected to even when you had no idea why, and that would usually do whatever I needed.

Choron is on Github now. You can try it out if you want. Well, if you have an installation of Rails 1.8. That might be difficult to get set up these days.

How it worked at first


Using Choron has a few steps:

1. Have an interminable meeting with your housemates in which you determine what fixed chores have to be done at what frequency.

Examples: "The table should be wiped off once a week." "The upstairs carpet should be vacuumed once a month."

People have a lot of disagreements and Feelings on this topic. (Before living with roommates, almost everyone thinks that their way of keeping their house clean is the universally correct way, and anyone who doesn't do it their way is a fool and/or pig, when in fact there are a thousand little ways that people can do this differently and still basically survive.) Making it all explicit means that the less-clean roommates don't get forced into doing way more work than they feel is reasonable, and the more-clean roommates get to put their cards on the table about what they really want.

Our group of roommates was great at having three-hour meetings with lively debate and productive results that we (mostly) adhered to. I have no idea if this works for anyone else!

2. Create the chores with a start date. This will also create an auction for the first instance of that chore.

3. Participate in auctions.

Here's how this works: You bid how much you want to be paid to do the chore. The lowest bidder wins. It's a second-price auction, to incentivize you to bid the real amount you want to be paid to do the chore.

During the auction, the lowest second-price bid so far is displayed, so you know whether bidding might make a difference.

When the auction is over, you get the chore contract, with a due date for when the chore needs to actually be done. When you click the "I did it" button, you get the number of chorons you bid. Also, everyone else is taxed to pay you for it.

Q: Why not just use money instead of chore points?
A: Because we wanted to convince our roommates to use it, and money is uncomfortable. But there was nothing stopping you from trading money for chorons!

Gaming the system

A problem with our auction system is that it's not incentive-compatible, nor is it strategy-proof, meaning, essentially, that you can game the system. We called this "bid sniping."

Here's an example. I knew that our roommate W would always bid 15 on "wipe down the microwave." The second-price bid, though, was 50, because no one else wanted to wipe down the microwave this week. I didn't really want to wipe down the microwave, but I also didn't want W to get a ton of money in taxes from me to do it. So I could bid 20, somewhat safe in the knowledge that I was reducing W's take and yet I probably wouldn't have to do it myself.

You can say "well, we're roommates! You should bid in good faith!" But it's much easier to say "you should bid in good faith" than to be absolutely sure whether you really would have bid that low (or high) if you didn't know that W did the same thing every week. Better to have an incentive-compatible system, so you don't have to feel guilt over whether you're doing it right or not. "This system works even if the participants are total psychopaths" means "you don't have to feel guilty for trying to optimize your take."

It's always gameable

We didn't look into this more until long after we'd moved out and stopped using Choron, but after hours and hours of research into mechanism design, my spouse discovered that incentive-compatibility in this situation was almost impossible. Alas!

The Hurwicz impossibility theorem is a result in mechanism design, that establishes the impossibility of having all of the following three properties:

1. Efficiency. Every chore is done by the person who hates it least.
2. Budget balance. Chorons are neither created nor destroyed.
3. Strategyproofness. You are incentivized to share your true preferences to get the best outcome for yourself; there's no advantage to hiding your preferences, nor can you make free money by knowing how your roommates are likely to bid.

Efficiency and budget balance are the two we effectively chose for Choron 1.0.

Unfortunately, there's really no way to get around budget balance in this situation. Consider: what if you chose to create chorons out of nothing to pay people, rather than taxing everyone else? Then bid sniping is less of a problem -- you don't care how much other people get paid for a chore because of taxation -- but you have a new problem: how do you tell how much work you're doing relative to your roommates? Effectively, you stop caring about your choron level relative to zero, and start caring about your chorons relative to your roommates' number of chorons. This invalidates a baseline assumption of second-price auctions: the assumption that you only care about how much money you have, not how much money other people have relative to you. If you care about other people's point totals, you might bid-snipe them just to decrease their take!

On the other hand, if you maintain the invariant that chorons can neither be created nor destroyed, each person can just track their choron level relative to zero.

We haven't discovered a way around this for our problem domain, but if you have one, or a reason why this analysis is wrong, please tell me. We'd love to know.

Complications

A problem arose sometime during the lifetime of Choron, which was this: Some chores had to be done an unknown number of times, at unknown intervals. The primary example of this was unloading the dishwasher and putting away clean dishes.

One of our roommates, J, was growing more and more resentful about how he did most of the dishwasher unloading, and was getting no points for it, while everyone else got points for things like ordering groceries1 and cleaning the microwave. There's an interesting lesson here: If you have a point system and some work isn't included in it, it's worse for the people doing that work than no point system at all!

So, being who we are, we set out to create a technical solution to this problem. My spouse spent many hours designing a mechanism, talking to our economist friends, and debating the issue with myself and our roommates, before emerging with a glorious new invention: the Shared Chore!

Shared Chores work like this:

1. You bid on them like a normal chore auction. But unlike a normal auction, your bid has TWO components: your own take, and a "pot" of points that will be distributed for actually doing the chore.

Bids are resolved by the total of the take + pot.

2. When you win the auction for the shared chore, you immediately receive your take. This is your compensation for being "in charge" of the chore, and picking a good pot amount that is big enough to incentivize yourself and/or your roommates to do it throughout the week. The rule was that if someone else noticed the shared chore not being done enough ("the dishwasher has been full of clean dishes for a day!") and they didn't find the pot enticing enough, they could instead bother the shared-chore-czar to do it.

3. Whenever you do the chore, you click the "I did it!" button for it. You then receive 1/N of the pot for that week, where N is the number of times everyone did the chore that week. It's payable at the end of the chore period.

Shared Chores have a few nice properties. You have an incentive to bid low, and specifically, to lower your cut to be arbitrarily low in exchange for having a larger pot. The main service that the shared-chore-czar provides is the service of correctly pricing the shared chore for everyone else (with a penalty of having to do it yourself if you priced it too low).

Q: Isn't this ridiculously complicated? Who would put up with this?
A: This is why you and I aren't roommates.

Trials and tribulations


Of course, like many young startups, Choron suffered from various critical production bugs that came to bite us in the ass when we least wanted them to.

Frozen

A few months into the first semester of using Choron, the holidays came around and we realized a couple of facts:

1. It was unfair to tax people for chores being done while they were away on vacation, since they weren't contributing to house uncleanliness.

2. We had no way to stop people from being taxed.

So we had a new, exciting hack weekend: Implement the ability to "freeze" people, so they wouldn't be taxed for any chores that were done during their vacation. We didn't actually implement UI support; we just ran an UPDATE statement on our SQLite database directly to freeze someone.

This was a little bit tricky, because the auctions and the chore events took place at different times, and sometimes people did their chores past the deadline. For ease of implementation, we decided that for whatever time period you were frozen, you would just not be taxed on whatever chores that were actually completed during that time. It was a little messy and didn't account for all the edge cases, but it was good enough and we could implement it easily.

So, this worked great, and we were really happy about it. No one had to be taxed when they were away on vacation. The system was fair, and so it was upheld.

A month or two later, we realized that one of our roommates had an anomalously high number of chorons. Somehow he'd been doing chores at roughly the same rate as everyone else, and yet his stash was increasing faster than ours.

Turns out he'd been frozen for about half a semester, because we forgot to change him back.

The fix

Step One of fixing this, of course, was to make sure it never happened again: by adding a huge YOU ARE FROZEN!!! banner to the header for frozen users.

Step Two was to reverse the chore transactions for the past month. Of course, we didn't have any sort of permanent record of people's choron levels, or how taxes had been calculated, or any backups of the database2... So we had to go through every chore that had been done in the past couple months (there were 10 or so per week) and figure the taxes on it by hand, then go into the database and manually add or subtract chorons from each user as appropriate.

By the way, on the subject of taxes: Chorons were integer values, but taxes were fractional -- so in order to tax people in integer amounts, we had a "bank" of leftover chorons from taxation events, which we reloaded chorons from to make it all average out. Which made reversing the transactions extra fun, since taxation had side effects in the form of bank changes.

Anyway, after that we installed a Ruby gem called Papertrail, which saves the state of your database every time anything changes in it. For our little 4 KB SQLite database of names and numbers, it was perfect.


Addition is hard

Of course, having installed Papertrail, we had set ourselves up for having to use it.

One day one of our roommates came and told us that something was weird about his Choron account. He'd clicked "I did it" on a chore and suddenly received about 1000 chorons, rather than the 100 or so he should have gotten for "go shopping at Costco."

You know what's important? Database transactions. You know what's especially important? Database transactions when you have a queue system that automatically retries on failure.

Upon careful analysis of a graph we painstakingly handcrafted out of the Papertrail data, it appeared his chorons had increased several times in the span of one minute. What happened was that his chorons increased early in the job, but something else failed in the process, causing the job to be retried... and him to receive more chorons.

At least this time we had the data to fix it. Without Papertrail we would've had to take his word for how many chorons he was supposed to have!

So did it work?


Yes.

There were six to eight people living in that house that used Choron while we lived there. I only actually lived there for a few months one semester, and the rest of the time I was a partial resident paying 1/4 rent to eat their food and hang out. I've lived with my parents, with other roomates in three or four situations (for much longer!), and with my spouse.

No place has ever felt more like home to me.

And a big part of this was the way the whole place just ticked over like clockwork. People did what they were supposed to, when they were supposed to; it stayed reasonably clean without overworking anyone; and we rarely argued over chores, or felt resentful about having to do them when roommates were dropping the ball. We made it work together. The house was a living thing, not just a place where we lived.


Cooperation, or the lack thereof


Most of our roommates participated in the system (there were 6-8 people living in the house, varying over time). We had one person who refused to ever participate in chore auctions, or, for that matter, really do any chores.

He had a reason for this, which was that he was rarely actually in the house. In retrospect, this was fairly reasonable, and yet he still probably should have been doing some small amount of work to pull his weight. His chorons went negative and steadily creeped down the longer we stayed in the house, because as far as I know he rarely did chores and never actually clicked "I did it" in the UI.

We could have implemented variable taxation rates to accommodate him, but I doubt it would have helped. His objection was to participating in a system, not just the unfairness of the system. And to be fair to him, the system was rather complex and annoying.

What we learned, ultimately, is that Choron has no power to enforce that chores get done, or compel people to do things they didn't want to. What it introduced was accountability. As long as you didn't straight-up lie on the web interface, what you got out of it was a reasonable accounting of how much work you had done relative to other people. So you could tell if you should be doing more to catch up, and also had a good way to see what would be most useful to everyone else. With that, and the motivation to stay on good terms with your roommates and keep the house running, it worked like a charm.

Exchanging favors

A great emergent feature of Choron was the exchanging of chorons for casual favors that otherwise might not have been done. As an example, two of the people living there had cars, and occasionally the rest of our roommates needed a ride to a subway stop. It became commonplace to ask, "Hey, would you give me a ride for 20 chorons?" The nice thing about this was: now you knew that the driver had no reason to feel resentful of you, and you didn't have to worry about taking advantage of them. If it wasn't worth it, they would negotiate up, or just say no. My spouse (who was among the carless) says he probably would have felt too guilty to ask if we didn't have Choron.

This was also a great lesson in YAGNI3 for us. We spent maybe a third of our time on Choron at the beginning implementing a system called "Bounties," a feature where an individual person could put up X chorons for something they wanted to be done. It was not used even once. It turns out that, in a house where everyone sees each other on a daily basis, you don't need to put up a bounty contract on a website; you just negotiate verbally and give the other person chorons when the task is done. Oops.

Looking to the future

After having great experiences with Choron for two years, you might say: why aren't we still using it?

Well, at first there were several reasons. I lived with some roommates who didn't want to participate in a system (and our house suffered for it). Then my spouse and I lived together and it seemed like overkill (though in retrospect, it would have been a good idea). Then we lived with some roommates and we tried to get it up and running, and well, Rails 1.8 is a real problem. Then we started thinking about rewriting it in Haskell.

Then we learned about some other strategies that other people we knew had for running chore systems, and thought, hey: what if it were a Dutch auction instead? Then you could just do the chore when you want and click "I did it", rather than having to participate in auctions and do it by a deadline.

And so then I finally snapped and rewrote it in Rust, and my spouse started working on it too. Now we're dogfooding Choron 2.0. We're moving in with friends later this year, and I hope to scale it up -- maybe even offer it to multiple households! -- once we work out some kinks.

And hopefully, in a couple years, I'll be writing an update with everything we've learned the second time around.




1We discovered after a while that for a house with seven grown adults, grocery delivery was definitely the way to go. It took several person-hours to do our shopping ourselves and delivery, for us, cost $7.
2With the exception of a backup in Dropbox which we'd made tried to make once several months prior.
3You Ain't Gonna Need It.

No comments :

Post a Comment