Log in

entries friends calendar profile Elf Sternberg's Pendorwright Projects Previous Previous
Elf M. Sternberg

I’ve discovered MyPy at work, and it works with Python 2.7 so amazingly well that I’m here to say, if you haven’t added it to your workflow, you need to immediately.

The last project I worked on at my day job, an automated inventory and services manager, was 2200 lines of one class object. When I was done, it was 1800 lines and 145 functions split over ten files, with separate classes for services and inventory, intake and output, local and network transformation, authorization, and utility. It’s primary purpose was to take in CSV (comma separated values– the text format for spreadsheets) and output JSON. We wanted to add other input formats, we wanted the output to be able to handle different formats as well, and we wanted to move the network transformation phase to an asynchronous handler with recovery-on-failure.

Doing that took a lot of heavy lifting. Figuring out what functions were for, what the dataflow looked like, what each step of the transformation required, how to handle conflicts with objects already in the inventory. Like most shops, we have rules about how to use docstrings that look a lot like jDoc, but by complete luck I found PEP-484 and MyPy the program that actually does Python type-hint checking, and immediately started using it aggressively.

The internals of the original, a one-off written for a single customer, had very strong assumptions about CSV inbound and JSON outbound. Functions were literally named with csv_ and json_ prefixes, even though internally everything was just Python dictionaries and lists!

I named things, and by their purpose: Classes called InventoryItem and TrackingService. I named collections of things. I named containers. And I added MyPy type hints to everything, like this (Code is from a personal project, mp_suggest, an early MP3 inventory manager I wrote a while ago.):

def make_album_deriver(opts, found, likely):
    # type: (Dict[Text, Text], Text, Text) -> Text
    if 'album' in opts:
        return opts[u'album']

    if 'usedir' in opts:
        return found

        return (ascii_or_nothing(likely) or sfix(found))

That little one-line comment there guarantees that anyone calling this function must send it what’s listed in the type line, and nothing else. MyPy will track back and make sure that the variables passed by the caller are actually created as a dictionary, a string, and a string! It will track forward and make sure that the receiver always uses the results as a string! It will ensure that the dictionary is created with strings as keys and values— no lists, no sets, no nested dictionaries are legal values. It will make sure that ascii_or_nothing and sfix take strings and return strings.

Programmers in dynamic, duck-typed languages like Python (and Javascript, Perl, Ruby, even Lisp) tend to assume we know what we’re doing. Given a problem, we come up with a solution, and then we start coding toward the solution, as if building and assembling a jigsaw puzzle along the way. On a very big project, we can miss things. Often, what we miss is error handling and corner cases. We can write a function and twenty minutes later call it, all the while assuming we can remember correctly what the calling protocol was. Often, we are wrong, and learning we’re wrong is sometimes a painstaking effort in type management. I believe half my debugging time is being a human typechecker: “Wait, it’s supposed to be passing back class X, but I’m getting a list. Why?”

PEP-484 eliminates all of that, and that makes PEP-484 the biggest leap forward in high-quality Python development since PEP-8. By eliminating the single most common class of running errors in all of Python, you can double your productivity. If you are not using MyPy, you are at a tactical disadvantage, and you will remain so until you adopt it.

Leave a comment
I finally watched Independence Day 2: Resurgence, and my initial hopes that it would be a fine movie were dashed by about the halfway point. Just a warning: this rant contains spoilers.
TL;DR: Independence Day 2: Resurgence draws you in with impressive and promising world-building in the first half hour, which it then completely discards and even contradicts in order to deliver an idiotic action-movie set-piece finale.
The film opens with an amazing bit of world-building. It's been twenty years since the first movie, and twenty years in the movie's universe. Humanity has taken apart much of the aliens' techonology and learned reliably from it. All the tech the aliens had, we now have. Plasma cannons, anti-grav, man-portable cannons, tractor beams, force shields, battery-sized fusion-based power plants, the whole kit the aliens brought with them in the first movie are now ours. We have bases on the moon, Mars, and even one of Saturn's moons. The alien tech is mostly hidden, incorporated into what we already do, so everything looks familiar; Marine One still looks like Marine One, it just doesn't use rotors anymore.

Even better, a few of the alien ships didn't crash; they managed to land, and humanity spent the next decade after the defeat of the mothership fighting wars with the aliens. Conveniently, this mostly happened in Africa and Southeast Asia. The result is that we have a lot of highly experienced alien hunters, in both high- and low-tech varieties, as well as a massive prison population of aliens. Up until this point, the world-building has been fairly well-handled.

The film goes off the rails when it's revealed that the alien ships are hiver ships; every ship has an alien queen, and when the queen is killed the rest of the aliens become comatose. Wait, what? Didn't the film also tell us that recently unqueened aliens become aggressive and continued fighting?

We're introduced to a new player, a refugee from another world and a previous alien attack. Her (voice is definitively female) species is completely digital and uploaded, yet for some reason needs an eight-foot-wide sphere to house its consciousness, has no ability to von-neumann up an entire starsystem in its defense, and lacks even rudimentary defenses.

It's also the biggest threat the aliens face, their boogieman in the silicon. So when the refugee reveals itself to humanity, the aliens respond with a devastating plasma weapons attack on the site from orbit, followed by high-yield fusion nukes, just to make sure, right?

Just kidding. In one of the most idiot plot moments in SF history, the alien queen leaves her vessel to take out the defenseless refugee on her own. We see her in one scene communing with advisors. Her advisors know that outside of her ship's powerful shields, the lesser shields of her shuttlecraft can be taken down by the humans' new weapons. Her advisors know that outside of her ship, she'll be vunerable. Her advisors know they have armed and armored personnel carriers that could invade and destroy the Cheyenne Mountain redoubt, because they already did so earlier in the film! But no, she has to handle this herself, and so chooses to take her personal Queen's "yacht" out.

There are a lot of other problems with the film. Apparently, despite all the tech they have, the aliens require fissionables to power their starships, and the bulk of Earth's trans-uranics are in its core, so Humanity's deadline is set by the mothership's massive drill operation. But that doesn't make sense; with their tech, there are lots of other ways to harvest fissionable material from the universe. When the refugee's ship is initially destroyed, no one from the moonbase goes out to look at the remains (WTF‽‽‽); David Levinson (Jeff Goldblum's character) has to have his hot-shot pilot friend steal a shuttlecraft to go check it out. And the movie is by Roland Emmerich; his penchant for crushing, burning, and mangling bystanders is only slightly restrained from the grotesqueries of 2012, but not by much.

Can we stop with the whole "alien queen" trope? Queens are not the brains of the hive: the hive is the brains of the hive. Queens are at best the uterus of the hive. Aliens, Independence Day, even Star Trek: First Contact have run out this idea. In any case, if you're injured neither your brain or your reproductive organs have evolved to leap out and avenge you.

Someone should make a Hellstrom's Hive movie and give us an alternative idea of what an SFnal "hive" would look like.

While the world-building, visuals, and science-fictional aspects are actually less insulting than those of Armageddon, The Transformers, or Battleship, the result is significantly less entertaining. Even the nostalgia-inducing aspects of seeing Jeff Goldblum, Vivaca Fox, Brent Spiner, Judd Hirsch and Bill Pullman doing their thing lack the emotional resonance needed to sustain it.

Tags: ,
Current Mood: annoyed annoyed

2 comments or Leave a comment
"The government should be run like a business!"

For eight years, we had a government run like a business. A business's mission is to make a profit before everything else, but a government's mission is different. A government's charter is to provide the foundation on which its citizens and businesses can thrive. You know, "To provide for the common defense, promote the general welfare, and secure the blessings of liberty."

To succeed, both require exceptionally talented, exceptionally detail-oriented people making the best decisions they can, always with both eyes on the mission, with the best information they can possibly get.

We had that.

We're about to find out what it's like when we don't.


1 comment or Leave a comment
In a comment about the recent Hamilton kerfluffle, conservative writer Rod Dreher said, "Brokeback Mountain did not change my mind one bit about same-sex marriage, because my views are not based on emotion."

That's a lie. In fact, it's one of the fundamental lies of our times: that human beings do things "without emotion." Men, especially. It's simply not true: underlying everything we do, absolutely everything, is emotion. There is no humanity without it. There is no such thing as consciousness without it. Every decision we make is tied to an emotional issue somewhere, because emotions are how human beings make decisions.

Dreher's claim is more along the lines of "I've made my decision to stay in the faith I've decided upon, and so my views on same sex marriage derive from that decision." But that decision is based on a feeling: the feeling that his orthodox Catholicism is the right and true state of being, and everyone who doesn't go along with his view is wrong. His commitment to his views is a source of pride, of satisfaction, and of contentment — all emotions. Every organization that earns fealty, be it a military or a religion, rides on that combinatoral ocean of pride and satisfaction, the notion that being a man means avoiding in-group conflicts, and creating conflict leads to terror because it means possibly depriving you of your community, your tribe, your very means of support.

Trump supporter Jesse Lee Peterson wrote "In the old days, men were not as emotional as they are now. They're worse than women! When I was growing up, had a man acted that way, we would take him out in the woods and beat him." You might recognize Jesse Lee Peterson's emotion: it's rage, which is notably one of the few emotions men are allowed to feel, and one of those privileged emotions men are allowed to feel without being labeled "emotional." Peterson is being very emotional. The men in his story are as well; they're exhibiting rage, along with shame, disgust and contempt.

When we say someone is "unemotional," what we're really saying is that they're engaged in the privileged emotions of masculinity: pride, reserve, contentment. Act like it, because your peers already terrify you if you don't.

Queer men like myself aren't "more emotional;" we're permitting ourselves a wider range of emotions than other men, because our status requires we either deal with the terror of stepping outside the box of performative masculinity, or surrender to the closet and its miseries. Black men aren't "more emotional;" they're acting outside of the emotional range white America would rather see from them (reserved and content with a lesser status), driven by a rage I can understand and with which I can empathize, if not feel as deeply as they do.

Consciousness is a quality we humans seem to possess in unique abundance. When we say, "I feel," we're expressing a conscious need at a conscious level, but we are feeling something all the time. Psychologists know this, advertisers know this. Politicians on the right know that making people fearful makes them want simple, authoritarian answers to their problems. It doesn't even have to be a political fear; asking people to walk over a frightening bridge makes them more likely to favor authoritarian policies in a questionnaire administered later the same day!

All consciousness is driven by emotion. All of it, without fail. Jesse Lee Patterson's man-shaped pack animals tearing into the weakling among them is pure, endocrinological emotion and nothing less. We are not thinking machines operating on pure rationality– and if we were, from where would our motives come? We are feeling machines that developed the capacity to think as our best tool, the one that put us at the top of the food chain, the one that keeps us there unless it leads to our crapping our own nest into an uninhabitable mess. Men who act "unemotional," who claim their decisions aren't driven by their feelings, are lying to you, and to themselves. What they're really doing is performing a pantomime of fearlessness because they're terrified of what would happen if they didn't.


4 comments or Leave a comment

Infoworld has an article entitled “The seven most vexing problems in programming.” The first two are “multithreading” and “closures.”

I call bullshit. Neither of those are hard problems. Both of those are problems of programmer laziness. (Not compiler laziness, of which I’ve recently become a fan.) It’s really hard to believe closures are a problem when we’ve had object oriented programming for over thirty years now and classes are nothing more than a specialized syntax for describing a closure.

You know what’s really broken about these two issues? Mutation. Objects (in the abstract, categorical sense, rather than the OO sense) changing and being changed in the code in such a way that it’s impossible to reason about the code in front of you. It’s impossible to say “This is what the object is.” It’s impossible to say “This is what this function does.”

There are times and places where mutation has a place, but they’re actually exceptionally rare. Mutuation can be used when performance is the only thing that matters; but if performance is the only thing that matters, then locks, semaphores and monitors are the performance drags and your code shouldn’t be involved with them.

Wayner’s complaint is wrong. These issues aren’t hard. These issues exist because programmers have been taught poorly. They’ve been taught that in-place mutation is the right way to do these things. They’ve been taught that lock-free data structures are “too hard” (but apparently debugging multithreaded is just fine). They’ve been taught to save unnecessary microcycles at the expense of their employers time and money.

The other day I debugged someone’s code where he looped through a very large list of objects. There was a bug where some of the first items didn’t get saved to the database with all the data the specification required. I discovered that he was pulling new data from the database every iteration, and saving some of it in a mutating array. Eventually it had enough data to do the job right, but not at the very beginning. When I asked him why he did it that way he said, “I’d have to iterate through the data twice, once to get all the keys, then to perform the updates. This was more efficient.”

It was also broken. “You mean, you accumulate mutations as you go along?” I said.

“Yes.” And then he broke out into a grin. “Isn’t that called evolution?”

“No,” I said. “99.999% of the time, that’s called cancer.”

And so it is with most programmers these days. They think cancer is preferable to thinking harder about the problem. I blame Python and Ruby, where mutation is easy, cheap, and often “gets the job done,” but makes it much harder to understand what the Hell is going on underneath the code.

1 comment or Leave a comment
When Barack Obama became the president of the United States, nobody who voted for his opponent killed themselves, or feared for their lives. There was lots of screaming about FEMA camps from the Alex Jones wing, and just as much screaming about "loss of religious autonomy" from the Christianist wing, and of course all the fear about "taking away our guns."

None of that happened. The people who voted against Barack Obama knew that the entrenched power in this country was on their side. That regardless of the power of the presidency, the congress, their state and local officials, the police and the judiciary, were overwhelming on their side. They knew that whatever happened, the power structures in this country would mostly still be on their side four years later.

You may remember during the George W. Bush administration when his surrogates complained that the press, in its criticism of Bush's actions in Iraq, "emboldened the terrorists." It was mostly bullshit, and attempt to discredit and unnerve the press into being silent on his mistakes.

The election of Trump has emboldened the terrorists within our own borders: the ones who delight in using terrorism as a tool to maintain their position as the ones with the power on their side.

We've already had reports of suicide. We've already had reports of at least one murder by a white nationalist attacking a Muslim man. Trump voters may not have "intended" this, but actions have consequences, and these are the consequences: the people with the least amount of power, the people who haven't got the courts, or the police, or the Congress, or the President, on their side, have been told in no uncertain terms that they don't matter.

It's the cruelty, stupid. When Barack Obama became president, he didn't come across as a cruel or heartless man, and in the years since he's shown grace, magnificence, and generosity the likes of which we may never see again. His supporters tried to emulate him, and for the most part we succeeded.

Trump's supporters are delighted in their desire to end the First Amendenment and to kick the crap out of protesters, harass, hurt, and kill minorities, forcibly destroy existing marriages between people of the same sex. Donald Trump wants a national database of all Muslims in the United States

The GOP-led House and Senate are full of men just waiting to overturn Roe v. Wade. Steve King, the infamously incendiary GOP representative from Iowa, can't wait to overturn Griswold v. Connecticut, and consequently make it illegal to give contraception to a minor. With the GOP in charge of both the legislature and the executive, wait until your parents or grandparents lose Medicare, Medicaid, and Social Security, as George W. Bush tried to do. With the GOP in charge of it all, watch them sell off the National Parks to multinational corporations as a way to "balance the budget." Attorney General Rudy Guiliani has already stated his desire to make Stop-and-Frisk By Militarized Police Officers the law of the land. Paul Ryan has already signed onto efforts to undo the Consumer Financial Protection Bureau and the Equal Employment Opportunity Commission. Say goodbye to collective bargaining, anywhere, by anyone. Maybe, just say goodbye.

It's the cruelty, stupid. We're about to watch a bunch of sex-hating, youth-hating, minority-hating white guys set the rules for the rest of us, and while there may be some friction between what their constituents voted for and what they want, they're the guys with the levers of power in hands. And they don't care who they hurt, because sex-hating, youth-hating, minority-hating white guys are gonna get so much gratifying frission from cruelly hippie-punching the other half of America, the slightly-more-than-half majority that voted for Hillary, for the next four years.

Current Mood: angry angry

3 comments or Leave a comment

Since I’m generally opposed to giving Hacker News oxygen, I refuse to comment there on a recent question, Do You Still Use UML?

As I’ve made clear, I have both anxiety and confidence about being an older developer in this world of high-tech startups and high-speed, high-burnout “only twentysomethings can do anything” world. Bloomberg the other day pointed out that almost all productivity gains over the past four years are in the hands of people like me, folks in our forties or later, folks who know stuff, folks with experience.

Anyway, to answer the question: Yes. When I was at CompuServe, they were kind and crazy enough to go through a full-on UML phase. It was a huge drag and it produced terrible software, mostly because the powers that be thought they could buy Rational Rose and jump straight into Class Diagrams and Sequence Charts without, you know, actually caring if anyone on the team knew about SOLID, DRY, KISS, YAGNI, etc. (I heard a great one the other day: TYKD, pronounced “Ticked:” Test, YAGNI, KISS, DRY. An acronym of acronyms.) The promised productivity never showed, and we ditched it after a year or so.

This cycle I have the responsibility for developing a fairly complicated piece of data analysis software, and while trying to describe my ideas for it, other members of the team weren’t getting it. Desperate to make myself clear, I actually plunked down $70 for a piece of UML software (StarUML, and pretty good, actually) and designed a sequence diagram to show how I expected the system to work with failures and fallbacks clearly described.

It was a rough diagram, and it had some ad-hockery because UML was designed before asynchronous and reactive programming became a thing. But when I showed it to my review committee, they were like, “Wow. That really does explain what’s happening here. That’s amazing. What is this?”

I explained what it was, and the reaction was, “Huh. So UML is useful?”

They approved my project quickly, and things are underway. And so far, it really is looking much like what I drew, which is fabulous. But I was able to get approval because I had bothered to learn UML.

Because I know things.

Leave a comment
I'm going to tell a story about a company that illustrates for me a key detail about the whole Trump vs. Clinton thing.

The CEO of this company was one of those rare men who had Steve Jobs' infamous reality distorting charisma. If you were in the same room with him and he was talking, you quickly started to believe every word he said. It wasn't as overpowering as Jobs'; the moment you left the room, you realized almost everything he had said was nonsense, but while he spoke everyone within reach of his voice was enraptured with his vision.

In the three years he was CEO, he used that charisma to plow through a succession of tall, blond, leggy secretaries. Five or six, if my memory serves me correctly. At company parties women warned each other not to be alone with him. He was a notorious womanizer who regarded the workpool as a hunting ground. I don't know if he ever quite reached the stage of sexual assault, but he was the very definition of a serial harasser.

Eventually, a sexual harassment lawsuit did ensue, and he was quietly shuffled off. So were a number of other men in the C-Suite who enabled his behavior. Here's the kicker: the company was hoping to IPO someday, and their main crime had not been to enable the CEO's behavior, but to have retained materially damaging comments in their email, in this case, snarky exchanges about how many women the CEO was banging.

Sexual harrassment by a powerful man in a leadership position was completely tolerable until it looked bad. What the board couldn't abide was that the other men had had poor judgement in their emails that made the company look bad, so they had to go as well.

Yes, one could spin it the other way and say they were let go because they knew about this highly embarrassing time bomb in their midst and did nothing about it; or because they knew he was a harasser and found it a matter of contempt, of envy, or of comedy, but never a moral issue. But what it really came down to was they wrote it down where it could be discovered. They misused email.

Today, that former CEO is again a CEO. I only know the fate of one of his enablers; he went on to run a small lifestyle web service that pays the bills, but it will never provide the high-flying, champagne-sipping, VC-hustling life he once lived.

Current Mood: insightful
Current Music: Brain.fm

Leave a comment
Last night, after the light rail dropped me off at my stop, as I was walking to my car a woman who had been on the train started walking toward the street, then stopped and asked me, "Excuse me, how far is it from here to Tacoma?"

"Tacoma?" I said. "Are you walking?" She nodded. "It's 15 miles from here to Tacoma."

"I thought... I thought Federal Way was just down that way."

"Yeah, about four miles. Then, Fife I think, then Tacoma." She was a thin woman wearing only a thin hoody. It was 51°F out, night was coming soon, and it was drizzling.

"Really 15 miles?"

"Yeah. This is exit... 151, and the dome's at 136, so, yeah, 15 miles. And that's before you actually get into the city. It's at least a half-day's walk."

"A half day?"

"I can do twenty miles on a good day with good boots, yeah."

She looked downtrodden. "Okay, thanks. Gotta cigarette?"

"I don't smoke, sorry."

She nodded and started walking.

I later realized I was off by one mile; the freeway exit is 150, so it was only 14 miles. I suspected she hadn't even paid to be on the train, but had ghosted, which is risky but if you're lucky the transit fare people will miss your train and won't check your pass.

Encounters like this are the opposite of dealing with crazy people on transit. I wanted to help, but I didn't feel I could offer it, and she didn't feel she could ask for more. We aren't taught how to deal with stories like this, and I wish I understood better why we aren't, and what I could have done differently.

Tags: ,
Current Mood: discontent discontent
Current Music: Brain.fm

3 comments or Leave a comment
The other day I broke my headphones (how is another story), so I went to Best Buy to get a new pair. At the register, I discovered that Best Buy had, like everyone else, gone to the chip-and-PIN system. I find C&P annoying; buying something is still a social activity, a brief exchange between two human beings. The swipe system was simple and transactive and allowed both involved to interact mostly with each other; C&P puts all of your attention on the chip reader. Starbucks understood this, and the C&P system they've rolled out is the least intrusive I've seen. Best Buy, on the other hand, has gone for an experience with its chip-and-PIN card readers that conveys a sense that Best Buy's hates you and hates having to deal with you. I have a rule that I will always buy from a brick and mortar over Amazon if it's within a twenty-minute drive. Best Buy's C&P system is so user-hostile I may reconsider that rule.

First, like almost every C&P system (but not, notably, Starbucks), you can't just shove your card in and ignore it until the transaction has ended. You have to look at the screen and wait until the machine says "Insert your card now." This is something UX designers call "active friction:" a transaction that used to be seamless now not only has its seams exposed but they're big enough for you to trip over them. Then it asks if I want the transaction in English or "Espanol" [sic]. It's Español, people; this is 2016 and Unicode is a thing!

The Best Buy C&P reader then asks if you want to sign up for a Best Buy credit card. Fuck no, don't ask me again. Upselling after the purchase transaction has begun is another hostile anti-pattern. Upselling by the machine is missing the point of having a human cashier!

After that, you get a screen that says "Do you want to treat this as a DEBIT card, or as a DEBIT MASTERCARD card?" I look at the cashier. "What does that mean? What's the difference?" He doesn't know, says it probably doesn't matter. I pick one.

The next page is the worst. "Accept Your Application? Yes / No."

Three screen back I was asked if I wanted to apply for a Best Buy credit card. Thinking I may have hit the wrong button, I immediately hit "No."

I get "Transaction cancelled."

The cashier says, "What happened?" I explained to him what happened, and he said, "Oh, that's not what that means. It wants you to confirm what kind of card you're using."

"It doesn't say that at all!"

"I know," he said. "It's awful."

So we go through the whole transaction again, I get past that screen, it asks if I want my receipt emailed. "Yes." The email entry screen is terrible, since the display is barely bigger than a cell phone. I'm repulsed again: can't they get my email address from the vendor?

Finally, "Enter your PIN." I do that.

"Use card ending in 1234 for this transaction?" Yes.

"Do you want to put all of the cost on this card?" Fuck, YES, already. "Transaction completed."


Compared to just handing over cash, there's so much friction in this exchange that it's hard to believe this is going to be the standard way we do business. It's so bad I would accuse Amazon of secretly engineering it to make the "One Click" buy-it-now process seem downright delightful. There are so many screens, so poorly worded, with so many easy misinterpretations and so many delays, that by the time I got to my car for deep loathing for what I had just experienced reinvigorated my desire to make my customers never have to suffer anything like that again.

Start with the initial impression that they don't really care that much for Spanish-speaking patrons (much less Vietnamese, Russian, Somali, Chinese, Korean, Ukrainian, Amharic, or Punjab, all of which are highly prevalent in my urban region). Add the deliberate confusion of the word "apply," the poor email address management, the sheer number of screens. Split-pay transactions like "Let me use up this gift card and I'll cover the rest with another card or cash" are pretty rare; to actually put this into the transaction flow that confronts every customer is goddamned stupid. That should be something the customer and cashier can work out together.

I'm a fairly technologically advanced human being. I write user interfaces like this for a living. That's my day job. I don't know if that makes me uniquely qualified to critique Best Buy's new C&P interface, but it shouldn't bewilder and upset me to use it. If I'm left confused by this point of sale tech, I can't begin to imagine what someone with far less education and experience goes through when they encounter this kind of bullshit.

Best Buy's point-of-sale chip-and-PIN interface communicates clearly that it doesn't trust the customer, expects the customer to be an idiot, and it expects to be able to use that idiocy to manipulate the customer into buying or agreeing to items they don't want. It also communicates clearly that it doesn't trust the cashier, either, by putting an unusual transaction workflow into the standard experience. So much attention is dedicated to managing this PoS (piece of [redacted]) that the usual pleasant social experience of dealing with a nice and competent cashier (and I got the impression mine was) was ruined. Until Best Buy changes their software, if you have to buy there, bring cash.

Current Location: Starbucks
Current Mood: annoyed annoyed

4 comments or Leave a comment