To celebrate our 100,000th Twitter follower in February, we offered to send out free stickers to dev.to users across the globe:
The Practical Dev@thepracticaldev
As promised— FREE STICKERS FOR ALL
16:29 PM - 22 Feb 2017
It felt like a great opportunity to reward our loyal followers by sending them a little something that physically connected them to the DEV community. Plus, how hard could it be to mail out some envelopes?
Within minutes of posting the tweet, we were inundated with sign-ups from all over the world; by the end of the day we had sticker package requests from 86 different countries.
Watching these orders pile up was exciting...but also a bit unnerving, since at that point the extent of our sticker distribution was handing them out here and there to various people with ties to the company. Now we had to figure out the postal idiosyncrasies of dozens of foreign countries, acquire hundreds of pounds (or rather kilograms, given our global clientele) of raw materials, and squeeze what would end up being nearly a thousand man-hours of labor into our already busy dev.to day-to-day. That monumental task, which we'd clearly underestimated, got off to a bad start with an...
The original version of our sign-up page had a bug that caused any form with the selected t-shirt size of unisex medium to register as invalid and the information dropped from our database. To make matters worse, we gave no indication to the user that his or her form had not been sent, so dozens of users were blissfully unaware that their sticker request had disappeared into thin air. We only realized once a few hundred forms had been submitted and there were no unisex mediums (the most popular size).
This led to the somewhat awkward half-measure of reaching out to folks who might have signed up for mediums to urge them to fill out the form again. And even when we fixed the
unisex_m bug, our form still had no way of...
By the beginning of the summer, dev.to/freestickers had address validation baked into so that verified locations are suggested as you fill in your answers:
But initially we rolled out a simpler, free-form template that put the onus on the user to provide a valid address.
Now you might think that most people know where they live, but different countries have different standards and conventions that didn't necessarily fit neatly into our USA-biased address/city/state format. So when we got inputs like
DespuÃ©s de hogares crea, segunda entrada mano derecha, Ãºltima casa verde (something about the last green house on the right according to Google Translate), we figured we had to validate these addresses.
We turned to SmartyStreets, an online address processor, to help us clean up and validate the user-inputted information. To our delight, it reported that nearly 100% of our US addresses were valid, but our international yield was closer to 80% and included puzzling verdicts like "partial" and "ambiguous" for some locations. In theory, we could ask those users to re-enter their addresses, but we were missing their IDs because...
Initially we assumed this endeavor could be housed by a single Excel file, but after validating several batches of users, it became obvious that this was an untenable approach. Each user had not only a row for the shipping info they provided, but also one for the slightly modified version to meet SmartyStreets' requirements, and another for the validator's output. Mix in different sets of data for US and non-US users, and suddenly our simple Excel file had a half-dozen sheets. Soon we couldn't change a single cell without summoning the dreaded spinning wheel of death.
Unfortunately, by the time we realized a single Excel file was insufficient, we'd already copy and pasted data in and out of SmartyStreets and our label-printer multiple times without bringing user IDs, our primary key, along each time. So even if we had a list of unverified addresses, we'd have to match them with other, slightly different columns in our database just to retrieve the IDs. We were left with a bunch of overlapping Excel files, only some of which had user IDs:
And even when we did have complete, validated addresses we had to deal with...
The manner in which to encode characters can be a trivial choice in scenarios where just a fraction of your string data isn't covered by [A-Z][0-9]. But when you're sending mail to Ciudad AcuÃ±a in Mexico, ÐšÐ¸ÐµÐ² in Ukraine, MÃ¶nchengladbach in Germany, SÃ£o JosÃ© in Brazil, and å—äº¬å¸‚ in China, encoding is the difference between a real location and pure gibberish.
But we didn't put all that together that until well after the fact. In order to print addresses, we'd opened the data in Excel, copy and pasted it into the SmartyStreets web app, copy and pasted the result back into Excel, saved it as a CSV, manipulated it further in R, and then loaded it into our Dymo label-printing software. By then it had been encoded and re-encoded half a dozen times using various standards, leaving some addresses in a state of absolute incoherence:
Many addresses had to just be scrapped, since we figured the mailman didn't know where house number Ã˜Â§ÃšÃ˜Â®Ã˜Ãš was located. And, as you'd expect, there were plenty of addresses somewhere between perfect and illegible which we released into the great postal unknown with our fingers crossed. Our users were thankful, albeit a little amused, when they arrived:
And if we did manage to encode each character cleanly, sometimes we still had to worry about...
Again, our ignorance of international mailing standards turned out to be a major weakness. Our form asks for two address lines and a city and state, per American standards. But there are far more ways to define physical locations beyond our borders, including localities, provinces, regions, districts, zones, and areas. SmartyStreets filled these fields in their response CSV where applicable, but we needed a blanket strategy for converting these to shipping labels–we couldn't map "district" to an address line if only a few of our recipients even had one.
What's more, two address lines is insufficient in many places, and sometimes as many as six or seven address fields would be returned by the validator. Since we couldn't reasonably fit that many lines on a shipping label, we had to write a janky Excel formula that created a bunch of mirror fields for address lines that weren't just repeats of city or zip code, and then concatenated them into a single address line.
This worked...sort of. Occasionally these "catch-all" address lines would grow so long that the label maker was forced to make the text unreadably small:
If an address was lucky enough to survive validation, encoding, and formatting, it still had to be printed and affixed to an envelope full of stickers, which required...
Some of the raw materials were heavy but easy to procure: large boxes of envelopes, cardboard inserts, labels, and stickers were delivered to our door and then stored wherever our modest office space could accommodate them–on a bookshelf, next to the fridge, or (more often than we'd like to admit) just stacked unceremoniously in the middle of the room.
Other stuff was physically unimposing but difficult to acquire, such as thousands of moon stamps, which had to be picked up in-person at the main New York City USPS office on the other side of town by someone with ID.
Then we had to turn these disparate parts into mailable sticker packs. Creating a few envelopes was something the dev.to staff could do in their spare time. Packing ten thousand was something we needed help with. A couple of friends volunteered some hours, but to get the job done in a reasonable timeframe we needed to hire some labor. We turned to TaskRabbit, where we enlisted people with highly rated organizational skills. Our Taskers were great – friendly folks that worked hard for hours at a time – but being outnumbered by strangers in the office was something we had to get used to.
Ultimately, packaging was one of the least stressful aspects of the process, and a lot of us took a break from staring at our monitors to listen to some music and help out every now and then. But on several days we had to ask everyone to work from home because the packing process was turning our modest office into a tornado of discarded labels and stamps:
Of course all the bags in that picture had to make their way to the post office, which leads us to...
Sometimes we scheduled pick-ups to clear our office of outgoing sticker packs, but when we really wanted to get them out quickly, there was no other option besides walking them the five or six blocks to the local post office. Have you ever carried a bag full of a thousand envelopes? It's damn heavy.
Plus, the first time we hauled those bags over, the woman at the counter told us that our international letters would not send because we'd used three-letter codes instead of spelling out country names. Turns out she was wrong, but for a day or two we wondered if we'd just botched every single outgoing piece of mail.
And even if we weren't chastised for not writing out country names, the employees at the post office usually gave us some quizzical looks. And who can blame them? Groaning under the weight of giant bags full of black envelopes on our shoulders, we looked like some bizarre combination of Santa Claus and the Grim Reaper!
And, as you might imagine, if you send out a lot of half-validated, poorly encoded, unconventionally formatted letters, you get a lot of them back:
Sometimes the letters were returned for other reasons though. Did you know that the US suspended postal service to Guatemala? We didn't!
Despite these relative missteps, we’re happy to report that over 95% of letters made it to their final destination. Still, that leaves a lot of folks who have very patiently waited for their packages and haven’t received them. Which is why we'd like to apologize and make things right by explaining...
We've ended the free stickers campaign for new users. But if you were already a dev.to user who requested stickers and never received them, you can visit dev.to/freestickers and (re)validate your address so we can finally send you your stickers.
If you ordered in the month of July, give it a week before marking yourself unfulfilled and re-requesting stickers, since we just sent out a bunch and they may be en route.
Note: While we can tell who originally requested stickers, we cannot verify if they arrived so we're relying on users to be honest about whether they received theirs. Plus supplies are limited, so anyone trying to get a second set is really only taking them from someone who doesn't have any. ðŸ˜”
And finally a few thank yous are in order. First we'd like to thank the companies that co-sponsored our original sticker batches: Clarifai, Circle CI, and Cloudinary. Their original investment really helped get this campaign off the ground.
We'd also like to thank stickermule who printed all of our lovely stickers. We tried out a bunch of different sticker companies and concluded that they had the best combination of quality and service.
And we'd like to thank the dev.to users who waited patiently for their stickers, some of which never arrived. In truth this was an expensive endeavor, from the raw materials, to the various shipping difficulties, to the labor exhausted on everything from packing envelopes to responding to emails with the subject line
But seeing you guys post pictures of the stickers on your laptops (or motorcycle helmets or bumpers or doors or limbs or nameplates or bicycles or water bottles or chargers or file cabinets or nightstands or desks or server racks or guitars or motorbikes or computer science departments or kegerators) made the whole thing totally worth it. ðŸ’•
PeerDependencies, one of the terms that brought up confusion to my mind when I first got the PeerDependency warning in my terminal. In this blog post I'll write down what I found out about NodeJS PeerDependencies in a way that also might help others to better understand this topic.