23.02.2016 Views

Hacker Bits, March 2016

HACKER BITS is the monthly magazine that gives you the hottest technology and startup stories straight from Hacker News. We select from the top voted stories for you and publish them in an easy-to-read magazine format. Get HACKER BITS delivered to your inbox every month! For more, visit hackerbits.com.

HACKER BITS is the monthly magazine that gives you the hottest technology and startup stories straight from Hacker News. We select from the top voted stories for you and publish them in an easy-to-read magazine format.

Get HACKER BITS delivered to your inbox every month! For more, visit hackerbits.com.

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

hacker bits<br />

<strong>March</strong> <strong>2016</strong>


new bits<br />

Wow! What a month! Thanks to you, the first issue of<br />

<strong>Hacker</strong> <strong>Bits</strong> has been viewed over 2,000 times! We<br />

are beyond thrilled (and surprised!) by the reception<br />

the magazine has received and so without further ado, here’s<br />

what we have in store for the 2nd issue of <strong>Hacker</strong> <strong>Bits</strong>!<br />

As always, this month’s issue comprises a round-up of the<br />

biggest tech stories that have set the Internet ablaze, including<br />

Paul Jones’s insightful analysis on Apple’s declining software<br />

quality, and Ricky Yean’s heartfelt account about privilege and<br />

inequality in Silicon Valley.<br />

There’s also a fascinating report on t-shirt sizes by Threadbase<br />

and a mind-bogglingly inventive commentary on mail<br />

forwarding by Rémi Parmentier.<br />

So dive in and enjoy the issue! And don’t forget to let us know<br />

what else you’d like to see in <strong>Hacker</strong> <strong>Bits</strong>!<br />

— Maureen and Ray<br />

us@hackerbits.com<br />

2 hacker bits


hacker bits<br />

<strong>March</strong> <strong>2016</strong><br />

Steve Ridout<br />

Ricky Yean<br />

Threadbase<br />

Rémi Parmentier<br />

Cory House<br />

Paul Jones<br />

Cam Jackson<br />

Jessica Abel<br />

Giles Clement<br />

Mike Hadlow<br />

Joe Armstrong<br />

6<br />

8<br />

12<br />

16<br />

22<br />

26<br />

29<br />

36<br />

39<br />

43<br />

46<br />

3 years as a one man startup<br />

Privilege and inequality in Silicon Valley<br />

T-shirts unravelled<br />

Super Mail Forward: An email that evolves<br />

as you forward it<br />

Angular 2 versus React: There will be<br />

blood<br />

Apple’s declining software quality<br />

9 things every React.js beginner should<br />

know<br />

Imagining your future projects is holding<br />

you back<br />

I built myself a 16×20-inch camera in 10<br />

hours<br />

Heisenberg developers<br />

A badass way to connect programs<br />

together<br />

hacker bits<br />

3


contributor bits<br />

Steve Ridout<br />

Started programming as a kid, copying<br />

BASIC games line-by-line from<br />

computer magazines. After getting his<br />

PhD he worked at a university creating<br />

software to simulate mechanical engineering<br />

problems, and later at Mendeley<br />

where he helped create reference<br />

management software used by millions<br />

of researchers around the world.<br />

Readlang is his first attempt starting an<br />

online business of his own.<br />

Cory House<br />

Author of “Building Applications with<br />

React and Flux”, “Clean Code: Writing<br />

Code for Humans” and multiple other<br />

courses on Pluralsight. He is a Software<br />

Architect at VinSolutions and<br />

trains software developers internationally<br />

on software practices like frontend<br />

development and clean coding.<br />

Cory is a Microsoft MVP, Telerik<br />

Developer Expert, and founder of outlierdeveloper.com.<br />

Paul Jones<br />

Programmer, writer, and technology<br />

enthusiast based in New York City.<br />

Paul blogs about Apple, software<br />

development, and the technology<br />

industry.<br />

Cam Jackson<br />

Software development consultant who<br />

loves working across the full stack -<br />

from UI design and development all<br />

the way to infrastructure automation.<br />

He has spoken for audiences large and<br />

small, including at 1stConf, DevOps<br />

Melbourne, Melbourne Functional<br />

Users Group, and as a university guest<br />

lecturer. He writes at camjackson.net.<br />

Jessica Abel<br />

Author of the graphic novel La Perdida<br />

and the comics documentary Out on<br />

the Wire, works with creative people to<br />

implement tools that help them actually<br />

make their work instead of just dreaming<br />

about it. Get a free worksheet to<br />

discover how you can work smarter and<br />

with less anxiety, here.<br />

Giles Clement<br />

Nashville-based photographer who’s<br />

often found touring the country with his<br />

furry four-legged friend Zeiss and a van<br />

full of cameras and lights. He specializes<br />

in portraiture, primarily done using<br />

tintype photography. You can find more<br />

of his work on his website, Facebook,<br />

Twitter, Instagram, and Flickr.<br />

4 hacker bits


Mike Hadlow<br />

British software architect and developer.<br />

He is the author of a successful<br />

open source project and specialises in<br />

building large-scale back-end systems.<br />

He lives in Sussex near the south coast<br />

of England with his wife, son and<br />

daughter.<br />

Joe Armstrong<br />

Inventor of the programming language<br />

Erlang. He has a PhD in computer<br />

science, and is Adjunct Professor of<br />

computer Science at the KTH Royal<br />

Institute of Technology. He has worked<br />

for many years as a Programmer, Academic<br />

and Entrepreneur.<br />

Threadbase<br />

A new company on a mission to help<br />

you find clothes that fit.<br />

Rémi Parmentier<br />

Web developer with an affection for<br />

emails. http://www.hteumeuleu.fr<br />

Ricky Yean<br />

Co-founder and CEO of PRX.co, a Y<br />

Combinator–backed startup offering<br />

PR on demand. Previously, he started<br />

Crowdbooster, a social media optimization<br />

service. Yean graduated from<br />

Stanford in 2010 with a BA in Science,<br />

Technology, and Society and serves<br />

on the board of BASES, a student<br />

entrepreneurship organization. He is a<br />

former entrepreneur-in-residence at the<br />

Stanford-StartX startup accelerator.<br />

Ray Li<br />

Curator<br />

Software engineer and data enthusiast<br />

who has been blogging at rayli.net<br />

for over a decade. He loves to learn,<br />

teach and grow. You’ll usually find<br />

him wrangling data, programming and<br />

lifehacking.<br />

Maureen Ker<br />

Editor<br />

Writer, editor, enthusiastic cook and<br />

collector of useless kitchen gadgets.<br />

She has authored 3 books and over 100<br />

articles. Her work has appeared in various<br />

children's and adult publications,<br />

including the New York Daily News.<br />

hacker bits<br />

5


STARTUP<br />

6 hacker bits


3 years as a<br />

one man startup<br />

By STEVE RIDOUT<br />

I’ve spent most of the past 3 years<br />

creating one language learning<br />

web-app, Readlang. I wrote about<br />

my struggle to get this off the ground<br />

almost two years ago and was thrilled<br />

with the response on <strong>Hacker</strong> News and<br />

elsewhere. I’ve been meaning to write<br />

a followup for a long time, but would<br />

always convince myself to wait…<br />

Just a couple more tweaks and<br />

usage will explode. Then I’ll<br />

have something to write about!<br />

Well here I am, three years later.<br />

Usage didn’t explode, but grew in fits<br />

and starts. I’ve worked hard for 3 years<br />

and am still making less than minimum<br />

wage. But that’s not as bad as it might<br />

sound.<br />

Money<br />

To survive as a bootstrapper, revenue is<br />

essential. But it’s often taboo, despite<br />

being very useful information. The<br />

problem is that if you report a low<br />

revenue, you may not be taken seriously.<br />

If you earn a lot, people listen but it<br />

invites competition and jealousy. I’m<br />

still on the low side, so here goes…<br />

New signups grew from 2,800 in<br />

year 1, to 9,300 joining in year 2, and<br />

36,800 joining in year 3. Revenue was<br />

roughly $700 in year 1, $4100 in year<br />

2, and $16500 in year 3. Expenses are<br />

low so the profit in year 3 was about<br />

$14500. That’s roughly equivalent to<br />

£9,700 British pounds. I’d earn more<br />

working 28 hours a week at minimum<br />

wage. I worked a lot more than that, so<br />

as an experienced software developer<br />

have paid a high opportunity cost.<br />

Will I continue with<br />

Readlang?<br />

I regularly question my decision to<br />

continue pouring so much time into<br />

Readlang. I wonder about the lucrative<br />

life of a contractor, or the cushy<br />

job of software developer at a large<br />

tech company. I wonder if I’m hurting<br />

my chances of future employment by<br />

working so long on my own.<br />

On the other hand, profits have<br />

grown 480% over the past year. If this<br />

continues, the future looks good. In<br />

year 4 (<strong>2016</strong>) I would make a typical<br />

UK software developer salary, and<br />

by the end of year 5 I’d be financially<br />

rewarded for the risk I’ve taken<br />

compared to being employed. But that’s<br />

still two years away. And is it even<br />

realistic to expect the trend to continue?<br />

I don’t know, but I’m making a bet<br />

that while I continue to work on it, the<br />

answer is yes.<br />

There are easier ways of making<br />

a living. But I’m proud of what I’m<br />

making, and it seems to genuinely help<br />

people to learn languages. Here are<br />

a couple of the many quotes I’ve received<br />

by email within the past month:<br />

En primeras palabras quiero<br />

decir, que me gusta muchísimo<br />

tu pagina. Es de verdad grande<br />

trabajo.<br />

If your Spanish isn’t great, try reading<br />

the above quote on Readlang.<br />

I’m in a polyglot group, and we<br />

all try different language tools<br />

constantly (Memrise, Anki, FluentU,<br />

etc), but I think Readlang<br />

has been the “stickiest” for the<br />

majority of us.<br />

On top of that, prolific language learner<br />

Alex Rawlings recently wrote of<br />

Readlang:<br />

This simple tool has changed the<br />

way I learn languages forever.<br />

Feedback like this assures me that I’m<br />

doing something right.<br />

Readlang is ramen profitable, helping<br />

more people every day, and there’s<br />

still plenty of room for improvement.<br />

Of course I’m continuing. •<br />

Reprinted with permission of the original author. First appeared at medium.com/@SteveRidout.<br />

hacker bits<br />

7


STARTUP<br />

Privilege and inequality<br />

in Silicon Valley<br />

Why “few successful startup founders<br />

grew up desperately poor”<br />

By RICKY YEAN<br />

My co-founder David and I<br />

both grew up in poverty and<br />

can call ourselves “battle-tested”<br />

when it comes to both life<br />

and startups, so when the talk in the<br />

Valley turned to income inequality, our<br />

ears perked up. For a moment, our two<br />

worlds were colliding. Here’s a quote<br />

from Paul Graham that got our attention.<br />

8 hacker bits


“<br />

test<br />

One example of a poor mindset is to minimize<br />

conflict because fucking up is costly<br />

and opportunities are hard to come by...<br />

“Closely related to poverty<br />

is lack of social mobility. I’ve<br />

seen this myself: you don’t have<br />

to grow up rich or even upper<br />

middle class to get rich as a<br />

startup founder, but few successful<br />

founders grew up desperately<br />

poor.” (link)<br />

Graham was right, and it’s a truth<br />

we’re intimately aware of as startup<br />

founders. Not only are the cards<br />

stacked against us to even have the<br />

opportunity to found a startup, but<br />

building and sustaining a company that<br />

is “designed to grow fast” is especially<br />

hard if you grew up desperately poor.<br />

David and I have been fighting this<br />

very idea since starting our company<br />

in 2010, and we’ve gotten pretty good<br />

at it. The main problem is what David<br />

and I call mindset inequality. To really<br />

understand it, I need to put you in my<br />

shoes. Let me take you on a personal<br />

journey.<br />

How I got here<br />

When I was 11, I moved to the United<br />

States with my dad. We were broke<br />

in Taiwan. I picked up the English<br />

language. My dad did not. He also<br />

didn’t work, so I started working<br />

when I was 14 by doing all kinds of<br />

odd jobs. On top of that, I did all the<br />

things immigrant kids are familiar with,<br />

like translating or simply handling<br />

all the business with landlords, bills,<br />

government services, insurance, etc. I<br />

was smart, but I wasn’t very good at<br />

school, and not knowing the language<br />

definitely didn’t help. My standardized<br />

scores were bad enough that when<br />

I decided to take school more seriously<br />

in high school, my counselor actively<br />

discouraged me from taking even just<br />

one honors-level course. I had to bring<br />

my dad to the office the next day and<br />

told him to pretend to say some words<br />

in Mandarin while I just demanded that<br />

I get put in an honors-level English<br />

class.<br />

I remember getting a B in that<br />

class, and that was enough to start<br />

taking some AP courses the next year.<br />

Unlike a lot of my peers at Stanford,<br />

high school was no joke for me. I was<br />

so underprepared and didn’t know<br />

how to learn that I basically committed<br />

to sleeping only three hours a night<br />

and re-read the same chapters in the<br />

textbook three times to force myself<br />

to memorize the material. I came to<br />

school every day with blood-shot eyes.<br />

One time I got a stress-induced bald<br />

spot that was pretty embarrassing, so I<br />

learned to develop a sense of humor.<br />

I found out about the SATs in<br />

10th grade. I took a mock test and<br />

scored around a 900 (out of 1600) and<br />

panicked. I took the money I made, and<br />

instead of helping to pay the bills, I<br />

paid for a few SAT classes at Elite Education<br />

Prep in my neighborhood. When<br />

it came time to renew, I told them I<br />

couldn’t pay anymore, but the amazing<br />

folks at Elite decided to just let me take<br />

classes for free and supplied me with<br />

all the study materials. I ultimately<br />

scored high enough that they put my<br />

picture up on the window to market to<br />

more students.<br />

You can imagine how lucky I felt<br />

when I got into Stanford on basically<br />

a full ride (Go Card!). I spent my first<br />

year perpetually awe-struck. All these<br />

amazing individuals to talk to. All these<br />

great resources to access. Stanford<br />

successfully created this physical and<br />

financial bubble around me that, for the<br />

first time in my life, I didn’t have to<br />

think too much about money. That was<br />

extremely empowering. I felt like I was<br />

just like my peers and that I could do<br />

anything. I can’t emphasize this enough<br />

so I’m just going to say it again. During<br />

my first year at Stanford, I felt so empowered<br />

I believed I could do anything.<br />

Of course, that was an illusion.<br />

Reality quickly set in. I took an<br />

“elective” course about Contemporary<br />

African Politics my first quarter and I<br />

received a C+ despite grade inflation.<br />

I didn’t know how to talk in a small<br />

discussion-based class of 12 students.<br />

I was scared. I was quiet. I didn’t<br />

know how to read or skim the volume<br />

of reading we were given, so I was<br />

stupidly trying to read Week 1 materials<br />

word-for-word during Week 4. I didn’t<br />

know how to think critically about what<br />

I was reading. At one point, Professor<br />

Weinstein sat me down during office<br />

hours to ask me what was wrong and<br />

how he could help. I didn’t even know<br />

what to tell him. In the dorm, where I<br />

was constantly inspired by my peers, I<br />

noticed that everyone I talked to played<br />

an instrument, which made me feel out<br />

of place. Instead of moving on, I surveyed<br />

the rest of my dorm to see who<br />

else played an instrument only to learn<br />

that I was the odd one out. Just a poor<br />

kid out of place. Not good enough.<br />

Sophomore year was when it all<br />

fell apart. Like many of my peers, I<br />

hacker bits<br />

9


She’d say,<br />

“We’re not meant to be successful,<br />

so what you’ve achieved<br />

“is good enough!”<br />

didn’t know what I wanted to do, so<br />

like them, I decided to do everything. I<br />

joined a bunch of clubs while the classes<br />

got harder. Soon enough I fell into<br />

a slump. When you’re in a slump, you<br />

start to look around and find even more<br />

ways to show yourself that you’re not<br />

good enough. I’d go to the same classes<br />

with friends and dormmates, but then<br />

I’d notice how fast they were learning<br />

the concepts while I was struggling. I<br />

asked one of them to tutor me, and even<br />

then I wasn’t keeping up. On top of<br />

that, the extracurricular commitments I<br />

picked up totally overwhelmed me, so I<br />

shirked many of my club duties. I also<br />

noticed that, in order to keep up socially,<br />

I had to spend money to participate<br />

in a lot of activities like going out to<br />

movies or dorm ski trips — and that<br />

was on top of having to buy my own<br />

books. I remember having to borrow<br />

a few hundred bucks from one of my<br />

best friends while I applied for another<br />

loan to cover the expenses. I remember<br />

running to the student loan office<br />

crying because I felt so bad. I told the<br />

loan officer I needed the money as<br />

soon as possible because I didn’t want<br />

the lack of money to ruin friendships<br />

the way it had ruined so many other<br />

things before. I spent the next 48 hours<br />

basically stressed as fuck until the loan<br />

money showed up in my account and I<br />

paid him back. He’s still one of my best<br />

friends to this day.<br />

The money problem was hanging<br />

over me the entire time in school. I’d<br />

get calls from home about money, but<br />

there wasn’t much I could do other than<br />

picking up a side tutoring gig. I remember<br />

lashing out at my dad on the phone<br />

because I didn’t want to carry him<br />

around as baggage while I was trying<br />

to get through Stanford like a “normal”<br />

student. I didn’t want to have a lesser,<br />

second-rate experience. I so desperately<br />

wanted to maintain the illusion that I<br />

was on equal footing. I wanted to believe<br />

that there wasn’t anything holding<br />

me back from achieving and that I’d<br />

get through this.<br />

I did.<br />

I went on a trip led by Kimber<br />

Lockhart and Andi Kleissner to visit<br />

social enterprises in the Bay Area. I<br />

learned about entrepreneurship through<br />

companies like Kiva and World of<br />

Good. The two of them suggested that<br />

I join BASES, the Stanford student<br />

group for entrepreneurial minds. Then<br />

I fell in love. I attended Y Combinator’s<br />

Startup School the same year<br />

Jeff Bezos announced Amazon Web<br />

Services. I ended up finding my niche<br />

at Stanford as the co-president for both<br />

BASES and AKPsi, a coed pre-business<br />

fraternity. I worked as a young VC at<br />

Alsop Louie Partners, where Stewart<br />

Alsop gave me my first Apple product<br />

(his old Macbook), then I interned at<br />

Eventbrite, where Kevin Hartz saw<br />

something in me that I wasn’t even<br />

aware myself. I started working on<br />

side projects with a very impressive<br />

individual I met named David Tran. I<br />

became “that guy” on campus who was<br />

the most gung-ho about entrepreneurship.<br />

I learned how to execute, and then<br />

I learned how to lead. Our side project<br />

became a startup that got funded by Y<br />

Combinator. We raised money, built<br />

Crowdbooster to profitability, and now<br />

we’re building PRX, which is an even<br />

bigger idea to offer PR services on demand.<br />

It’s well on its way. We can talk<br />

about that in my next post.<br />

Mindset inequality<br />

With that story in mind, now let<br />

me explain mindset inequality and why<br />

“very few successful founders grew up<br />

desperately poor.”<br />

I was lucky that I found something<br />

I loved in entrepreneurship, which<br />

helped me focus my energies away<br />

from academic classes. I was lucky I<br />

found out that I was good with people<br />

and loved organizing and leading teams<br />

to achieve great things. I was lucky<br />

there were no other traumatic events<br />

that knocked me further into the deep<br />

end. I could’ve easily given into the realities,<br />

dropped out, or just given up the<br />

illusion and adjusted my goals — except<br />

I chose to start a company. Starting a<br />

company for me was the ultimate declaration<br />

that I wanted to hold on to the<br />

illusion and continued to believe that I<br />

could do anything.<br />

But because I fought hard to maintain<br />

this illusion for myself all through<br />

Stanford and while building the startup,<br />

I’m extremely aware of the disconnect.<br />

The world is clearly not a level playing<br />

field. Just with myself and my experi-<br />

10 hacker bits


ence, I can see a lot of buggy code in<br />

my mind’s operating system that isn’t<br />

conducive to building a successful<br />

startup. Here are some of the issues<br />

with my default mindset that I’ve had<br />

to fix over time.<br />

One example of a poor mindset is<br />

to minimize conflict because fucking<br />

up is costly and opportunities are hard<br />

to come by, so it’s been a challenge putting<br />

my ideas out there and defending<br />

them. I often hear about people having<br />

intelligent conversations at home with<br />

their parents. I never ate at the dinner<br />

table because we didn’t have one in the<br />

one-bedroom apartment that I shared<br />

with my dad. You can imagine how this<br />

translates to pitching your startup. The<br />

idea<br />

“<br />

of putting my grand idea out there<br />

and vigorously defending it to investors<br />

trying to tear it apart was new and<br />

counterintuitive.<br />

Related to that, a poor founder<br />

tends to be less confident. My mom,<br />

who didn’t go to college, used to say<br />

this to me, and it bothered me a lot.<br />

She’d say, “We’re not meant to be<br />

successful, so what you’ve achieved<br />

is good enough!” Compare that level<br />

of confidence to a kid with successful<br />

parents who’d say something along the<br />

lines of “If you can believe it, you can<br />

achieve it!” Now imagine walking into<br />

a VC office having to compete with that<br />

kid. He’s so convinced that he’s going<br />

to change the world, and that’s going to<br />

show in his pitch. You can’t just muster<br />

up that confidence on the spot.<br />

Then there’s knowing how to<br />

manage resources. Being poor makes<br />

you suck at using money as a resource.<br />

My time was always cheaper growing<br />

up, so I’d rather spend time than<br />

spend money. I had to fix this when we<br />

raised our first seed round, but it took<br />

quite some time. A simple decision<br />

to hire, for example, took a very long<br />

time to the point that it cost us growth.<br />

Then there are also human resources,<br />

networks of people who can help you.<br />

Again, growing up poor meant that<br />

there weren’t successful aunts and<br />

uncles who could show me the ways of<br />

the world or even give me a little nudge<br />

in the right direction. I’ve had to learn<br />

to work the room, to talk to and talk<br />

like a successful person, and to know<br />

how to ask for help.<br />

I’ve also noticed the huge difference<br />

having some built-in resources can<br />

to work at safer and more lucrative careers<br />

that would be of more immediate<br />

help to your family. It’s very irresponsible<br />

to pursue the startup path, and even<br />

if you do succeed in upgrading your<br />

mind software to get rid of all the bugs<br />

I mentioned above, you start to sound<br />

and act differently from the people<br />

you grew up with. You might even get<br />

accused of losing your identity. This is<br />

why successful rappers are told they’re<br />

turning their backs on their communities<br />

all the time.<br />

All of this contributes to the mindset<br />

inequality that founders like David<br />

and me have to overcome. We think<br />

this is the reason why poor founders<br />

tend not to be successful. Fortunately<br />

for us, we consider this the biggest<br />

...inequalities that live in your mind<br />

can keep the deck stacked against you...<br />

make. I don’t have “friends and family”<br />

money to get going. In fact, I’m<br />

sending money to my dad every month<br />

from the measly income I take out from<br />

my startup. Knowing that you have<br />

“friends and family” money to get going<br />

or even some family money to help<br />

you when you fail makes it that much<br />

easier to be more risk-seeking and build<br />

the appetite for hyper-growth startups.<br />

Most of the time, potential founders<br />

who share my background tend to work<br />

at lucrative jobs in finance or tech until<br />

they can take care of everyone in their<br />

families before they even dream about<br />

taking more risks — if they ever get<br />

there.<br />

Finally, there’s the constant guilt.<br />

If you have a Stanford degree and share<br />

my background, you’re likely the only<br />

one they can count on at home. You<br />

most likely would have the opportunity<br />

chip on our shoulders. Known bug in<br />

our mind software. We’ve overcome so<br />

many of these issues, and we’ll keep<br />

chipping away at it until we win. But<br />

for others, I think it’s important to note<br />

this: tangible inequalities — that which<br />

can be seen and measured, like money<br />

or access — get the majority of the attention,<br />

and deservedly so. But inequalities<br />

that live in your mind can keep<br />

the deck stacked against you long after<br />

you’ve made it out of the one-room<br />

apartment you shared with your dad.<br />

This is insidious, difficult-to-discuss,<br />

and takes a long essay to explain.<br />

David and I are living proof that if<br />

we can upgrade and improve the way<br />

we think, and overcome our mindset<br />

inequality, then maybe we can help others<br />

do the same. For me, that starts with<br />

sharing my story so far. Stay tuned. •<br />

Reprinted with permission of the original author. First appeared at medium.com/@rickyyean.<br />

hacker bits<br />

11


STARTUP<br />

T-shirts unravelled<br />

By THREADBASE<br />

We washed, dried, measured<br />

and weighed 800 of the<br />

most popular men's t-shirts<br />

available online. The shirts included a<br />

wide variety of price points ($5-$50),<br />

sizes (XXS up to 6XL) and fits ("slim",<br />

"tall", "relaxed", etc.). After compiling<br />

the data, we worked with beta testers<br />

in NYC to develop an algorithm that<br />

could recommend t-shirt brands and<br />

sizes for a wide range of body types.<br />

We're still tweaking the math on that<br />

algorithm, but in the meantime, we<br />

thought we'd share some of the data<br />

that has surfaced from our project so<br />

far.<br />

12 hacker bits


Figure 1: Evolution of 10 different t-shirts over 16 washes<br />

T-shirts widen and shorten<br />

over time<br />

T-shirts change in consistent ways over<br />

time. Each time a t-shirt is washed,<br />

it shrinks, and each time it is worn, it<br />

expands. The expansion in the chest is<br />

almost 2x more than the expansion in<br />

the length and most of that expansion<br />

happens in the first two hours of wear.<br />

What surprised us was that over<br />

the course of many wash cycles, the<br />

chest and waist will drift wider and<br />

the length will drift shorter. The chart<br />

in Figure 1 shows the evolution of<br />

10 different t-shirts over 16 washes,<br />

averaged to one line. (We calibrate our<br />

search results to the dotted lines shown<br />

below).<br />

A Zara XL is like a<br />

J. Crew Medium<br />

No two brands have the same sizing<br />

system, and the differences between<br />

them can be vast. The chart below pro-<br />

vides a breakdown of chest measurements<br />

for sizes Small, Medium, Large<br />

and XL. The chest is measured as the<br />

distance between the shirt's arm seams.<br />

See Figure 2.<br />

Expressed as chest x length, the<br />

average Small is 19.0" x 26.3", the<br />

average Medium is 20.5" x 27.1", the<br />

average Large is 22.0" x 27.8", the<br />

average XL is 23.5" x 28.6". The length<br />

breakdown is provided below. See<br />

Figure 3.<br />

Fabric weight and price<br />

have no relationship<br />

One of our assumptions going into the<br />

project was that cheaper t-shirts would<br />

weigh less (per square yard). In fact,<br />

heavier t-shirts were less expensive, on<br />

average, than lighter ones (overall the<br />

correlation is very weak). Commodity<br />

cotton is cheap right now (only $0.70/<br />

lb), so raw materials comprise only a<br />

tiny portion of a manufacturer's cost<br />

structure. See Figure 4.<br />

The culprit is<br />

manufacturing variance<br />

You may have had this experience before:<br />

You buy two identical articles of<br />

clothing. They are the same brand, style<br />

and size -- maybe even the same color.<br />

They are exactly the same except that<br />

one fits, and the other does not. The<br />

problem is manufacturing variance.<br />

To test manufacturing variance,<br />

we measured 20 identical new t-shirts.<br />

These shirts were priced in the $20<br />

range. Figure 5 depicts the distribution<br />

in chest width and length, which each<br />

have a standard deviation of about one<br />

fifth of an inch.<br />

It's probably more helpful to think<br />

about the size of a particular shirt as a<br />

distribution, rather than an exact number.<br />

Maximize your chance of success<br />

as a consumer by buying t-shirts where<br />

the average is a good fit. This way only<br />

extreme outliers won't fit you well.<br />

hacker bits<br />

13


Figure 2: T-shirt chest width<br />

Figure 3: T-shirt body length<br />

14 hacker bits


Figure 4: Fabric weight vs. price<br />

Figure 6: T-shirt shrinkage from first wash<br />

Figure 5: Distribution in chest width and length<br />

It's the dryer, not the washer, that<br />

shrinks t-shirts<br />

One thing you hear everywhere is that washing clothes<br />

in hot water will cause them to shrink. While hot water<br />

may cause shrinkage in wool garments, for cotton and<br />

polyester t-shirts, the washer settings don't make a big<br />

difference. The biggest determinant of shrinkage is<br />

whether the shirt went in the dryer or not. (We wash and<br />

dry all t-shirts using a warm wash and normal/warm dry<br />

cycle). •<br />

Reprinted with permission of the original author. First appeared at threadbase.com.<br />

hacker bits<br />

15


INTERESTING<br />

Super Mail Forward:<br />

An email that evolves<br />

as you forward it<br />

By RÉMI PARMENTIER<br />

Last year, Litmus held a community<br />

contest which theme was<br />

“Emails Worth Forwarding”. In<br />

order to participate, I created an email<br />

I called Super Mail Forward. It’s an<br />

email you can forward between the<br />

desktop webmails of Gmail, Yahoo,<br />

Outlook.com and AOL, evolving with<br />

each forward. It’s a fantastic exercise<br />

that taught me a lot of things specific to<br />

these webmails. Here are a few details<br />

to the right.<br />

The email is composed of four<br />

question blocks (from Super Mario<br />

World). Every time you forward the<br />

email on the expected webmail, in the<br />

right order, the first unopened block<br />

will be transformed into a mushroom of<br />

a different color. If you send the email<br />

on one of the four supported webmails,<br />

but not in the expected order, the<br />

question block corresponding to the<br />

expected position for this webmail will<br />

turn red.<br />

I wanted to make this exercise in<br />

order to see how many times you could<br />

Super Mail Forward<br />

16 hacker bits


If you send the email first in Gmail, the block corresponding to Gmail’s order turns red<br />

forward an email before its code, transformed by webmails,<br />

would become an incomprehensible mess. And to my biggest<br />

surprise, you can go pretty far.<br />

In fact, webmails like Yahoo, Outlook.com or AOL don’t<br />

deteriorate the HTML code of an email when forwarding it<br />

more than when they receive it in the first place. This means<br />

that since Outlook.com filters the CSS background-image<br />

property, this property will also be absent when you forward<br />

an email from Outlook.com.<br />

The only exception to this behavior is Gmail. On top of<br />

filtering any class or id attributes (which is in itself already<br />

pretty annoying), Gmail will remove any tag and<br />

any attribute usually supported (like lang or aria-labelledby)<br />

when you forward an email. So I quickly realized that if I<br />

wanted to include Gmail in my list of webmails supported by<br />

my email, it would inevitably be in the last position.<br />

I also picked AOL as the first webmail early on, as it’s<br />

the most permissive webmail regarding styles filtering. And<br />

after a lot of tests and hesitations, I picked Yahoo in second<br />

position and Outlook.com in third position.<br />

Each block of the email is composed of sixteen lines<br />

and sixteen columns. Each cell has a background color that<br />

changes depending on the current case :<br />

• either we’re on the right webmail in the expected order,<br />

• or we’re on one of the four supported webmails but not<br />

in the expected order,<br />

• or we’re not on one of the supported webmails.<br />

By default, each cell has a background property in a<br />

style attribute corresponding to its final state as desired in<br />

Gmail. The display in other clients is then handled with a<br />

play on classes. The final code for each cell looks like this:<br />

<br />

First step : AOL<br />

When landing on AOL, the webmail prefixes each selector.<br />

Thus, the selector .foo becomes .aolReplacedBody .foo.<br />

In order to target AOL and activate the first block, I used<br />

a filtering bug on AOL I discovered back then. When a<br />

background property contains a url() to an image within a<br />

tag, AOL incorrectly replaces the path of this image.<br />

Thereby, the following code…<br />

hacker bits<br />

17


AOL<br />

.block-fff {<br />

background:url('http://i.imgur.com/6qtuIRR.<br />

gif');<br />

}<br />

background:#fff;<br />

…is transformed by AOL into the following:<br />

.block-fff {<br />

background-image:url(&quot;http://i.<br />

imgur.com/6qtuIRR.gif&quot;);<br />

}<br />

background:#fff;<br />

Yes. AOL adds HTML higgledy-piggledy in a styles<br />

declaration. This behavior is quite inconvenient because it<br />

will cause modern browsers to ignore any following styles.<br />

But in my case, that suit me fine, and I was able to use this<br />

bug to my advantage. With the following code, I activate the<br />

mushroom for the first question block in every browser (with<br />

the rules .step1 .mushroom-X). And then, I immediately<br />

reactive the colors of the default block for the first step (with<br />

the rules .step1 .block-Y). But thanks to the background<br />

image bug, AOL will ignore these styles, and keep the mushroom<br />

colors.<br />

.step1 .mushroom-transparent {<br />

background:transparent!important; }<br />

.step1 .mushroom-000 { background:#000; }<br />

.step1 .mushroom-fff { background:#fff; }<br />

.step1 .mushroom-efe3af { background:#efe3af; }<br />

.step1 .mushroom-ee1c25 { background:#ee1c25; }<br />

.step1 .block-fff {<br />

background:url(‘http://i.imgur.com/6qtuIRR.<br />

gif');<br />

}<br />

background:#fff;<br />

.step1 .block-f8d81f { background:#f8d81f; }<br />

.step1 .block-d89f37 { background:#d89f37; }<br />

.step1 .block-000 { background:#000; }<br />

Since the making of this email, this bug was reported<br />

to AOL and they recently fixed it! This is a good news,<br />

of course, except that this means my forwardable email<br />

wouldn’t work anymore. Fortunately, I was able to find<br />

another hack in order to target AOL. Turns out AOL will<br />

18 hacker bits


Yahoo<br />

remove any tag that contains what it interprets as<br />

a wrong image URL for a background. Thus the following<br />

styles, redefining the colors of the question block, will be<br />

completely removed by AOL.<br />

<br />

.step1 { background:url(‘#’); }<br />

.step1 .W { background:#fff!important; }<br />

.step1 .X { background:#f8d81f!important; }<br />

.step1 .Y { background:#d89f37!important; }<br />

.step1 .Z { background:#000!important; }<br />

<br />

Second step : Yahoo<br />

When landing on Yahoo, the webmail once again prefixes<br />

each selector. The initial .foo selector now looks like the<br />

following.<br />

#yiv9876543210 .yiv9876543210aolReplacedBody<br />

.yiv9876543210foo { }<br />

Targeting Yahoo is a bit easier. Since last march, Yahoo<br />

supports media queries. But not every media queries. And<br />

when it encounters an unknown type of media, Yahoo will<br />

remove the aforementioned type. Thus, the following CSS<br />

code…<br />

@media yahoo {<br />

}<br />

.step2 .mushroom-fff { background:#fff; }<br />

…is transformed by Yahoo into:<br />

@media {<br />

}<br />

.step2 .mushroom-fff { background:#fff; }<br />

The styles contained in this media query will then only apply<br />

on Yahoo, and stay there for the next forward.<br />

Third step : Outlook.com<br />

When landing on Outlook.com, the webmail once again<br />

prefixes each selector. The initial .foo selector, transformed<br />

by AOL, then by Yahoo, and then by Outlook.com now looks<br />

like the following:<br />

hacker bits<br />

19


Outlook.com<br />

#ecxyiv9876543210 .ecxyiv9876543210aolReplacedBody<br />

.ecxyiv9876543210foo { }<br />

In order to persist until the next forward to Gmail, the<br />

activation of the mushroom on Outlook.com is handled with<br />

inline styles. Since the beginning, a second background<br />

property with an image was used to force the colors of the<br />

default block for this step. Outlook.com will remove this<br />

second property, leaving only the first one with the desired<br />

background color. The code of the following cell…<br />

<br />

…is thereby transformed by Outlook.com into:<br />

<br />

The problem is that this also applies for the last question<br />

block (supposed to be triggered only in Gmail). In order to<br />

fix this, I redefined styles in a tag with the colors of<br />

the default question block.<br />

Since the making of this email, Microsoft started phasing<br />

out Outlook.com to replace it with the same webmail as<br />

Office 365. In order to target Outlook.com to display a red<br />

question block when the email is not sent in the correct order,<br />

I used some CSS rules prefixed by .ecx. Since this was done<br />

only on Outlook.com, I had to find another way to target the<br />

new Outlook Web App client. It turns out that it will strip any<br />

attribute selector in a CSS rule. Thus, the following selector:<br />

[owa] .W { background:#fff!important; }<br />

…is transformed into:<br />

.W { background:#fff!important; }<br />

This is a pretty convenient way to target only Outlook Web<br />

App clients.<br />

Final step : Gmail<br />

When landing on Gmail, all the class attributes in the<br />

HTML are removed. There’s no longer any rule in a <br />

tag that applies. Only inline styles are left, corresponding to<br />

the final result desired.<br />

20 hacker bits


Voilà!<br />

Optimizations<br />

The longest part in creating this email was optimizing the<br />

code in order to not exceed the 100Kb limit above which<br />

webmails block part of the content. My first version was way<br />

above 160Kb. So I applied the following optimizations:<br />

• Use lang attributes instead of aria-labelledby for<br />

Gmail. This makes eleven characters less for every<br />

single cell.<br />

• Use shorter class names. I preferred using .A, .B, .C,<br />

… instead of .mushroom-black, .mushroom-white,<br />

.mushroom-red, …<br />

• Optimize the pixels grid in order to merge cells having<br />

a same color on both models (block and mushroom).<br />

The pixel grid is now composed of 155 cells, instead of<br />

256. It’s probably the most efficient optimization I made,<br />

but also the most complex to set up. In the end, the grid<br />

looks like this:<br />

Conclusion<br />

I spent around eight hours to create this email. Half of that<br />

time was spent to create a proof of concept, and the other<br />

half was to reproduce the pixel art and fine tune everything.<br />

The result is still very experimental, and I doubt there’s any<br />

application for this in a real email without spending another<br />

whole lot of time. But this was a fun way to learn new<br />

things. And it even helped AOL to fix a bug in their parser<br />

along the way!<br />

You can grab the full code of the final version here. Try<br />

playing with it and sending it to your own email adresses<br />

with services like Putsmail. •<br />

Optimized pixel grid<br />

Reprinted with permission of the original author. First appeared at medium.com/@hteumeuleu.<br />

hacker bits<br />

21


PROGRAMMING<br />

Angular 2 versus React:<br />

There will be blood<br />

By CORY HOUSE<br />

Angular 2 has reached Beta and<br />

appears poised to become the<br />

hot new framework of <strong>2016</strong>.<br />

It’s time for a showdown. Let’s see<br />

how it stacks up against 2015’s darling:<br />

React.<br />

Disclaimer: I enjoyed working<br />

in Angular 1 but switched to React in<br />

2015. I just published a Pluralsight<br />

course on React and Flux (free trial).<br />

So yes, I’m biased. But I’m attacking<br />

both sides.<br />

Alright, let’s do this. There will be<br />

blood.<br />

You’re comparing apples<br />

and orangutans!<br />

Sigh. Yes, Angular is a framework, React<br />

is a library. Some say this difference<br />

makes comparing them illogical. Not<br />

at all!<br />

Choosing between Angular and<br />

React is like choosing between<br />

buying an off-the-shelf computer<br />

and building your own with offthe-shelf<br />

parts.<br />

This post considers the merits of these<br />

two approaches. I compare React’s<br />

syntax and component model to Angular’s<br />

syntax and component model.<br />

This is like comparing an off-the-shelf<br />

computer’s CPU to a raw CPU. Apples<br />

to apples.<br />

Angular 2 advantages<br />

Let’s start by considering Angular 2’s<br />

advantages over React.<br />

Low decision fatigue<br />

Since Angular is a framework, it<br />

provides significantly more opinions<br />

and functionality out of the box. With<br />

React, you typically pull a number of<br />

other libraries off the shelf to build a<br />

real app. You’ll likely want libraries for<br />

routing, enforcing unidirectional flows,<br />

web API calls, testing, dependency<br />

management, and so on. The number of<br />

decisions is pretty overwhelming. This<br />

is why React has so many starter kits<br />

(I’ve published two).<br />

Angular offers more opinions<br />

out of the box, which helps you get<br />

started more quickly without feeling<br />

intimidated by decisions. This enforced<br />

consistency also helps new hires feel at<br />

home more quickly and makes switching<br />

developers between teams more<br />

practical.<br />

I admire how the Angular core<br />

team has embraced TypeScript, which<br />

leads to the next advantage…<br />

TypeScript = Clear path<br />

Sure, TypeScript isn’t loved by all, but<br />

Angular 2’s opinionated take on which<br />

flavor of JavaScript to use is a big win.<br />

React examples across the web are<br />

frustratingly inconsistent — it’s presented<br />

in ES5 and ES6 in roughly equal<br />

numbers, and it currently offers three<br />

different ways to declare components.<br />

This creates confusion for newcomers.<br />

(Angular also embraces decorators<br />

instead of extends — many would consider<br />

this a plus as well).<br />

While Angular 2 doesn’t require<br />

TypeScript, the Angular core team<br />

certainly embraces it and defaults to<br />

using TypeScript in documentation.<br />

This means related examples and open<br />

source projects are more likely to feel<br />

familiar and consistent. Angular already<br />

provides clear examples that show<br />

how to utilize the TypeScript compiler.<br />

22 hacker bits


(though admittedly, not everyone is<br />

embracing TypeScript yet, but I suspect<br />

shortly after launch it’ll become the<br />

de facto standard). This consistency<br />

should help avoid the confusion and decision<br />

overload that comes with getting<br />

started with React.<br />

Reduced churn<br />

2015 was the year of JavaScript fatigue.<br />

React was a key contributor. And since<br />

React has yet to reach a 1.0 release,<br />

more breaking changes are likely in the<br />

future. React’s ecosystem continues<br />

to churn at a rapid pace, particularly<br />

around the long list of Flux flavors and<br />

routing. This means anything you write<br />

in React today is likely to feel out of<br />

date or require breaking changes when<br />

React 1.0 is eventually released.<br />

In contrast, Angular 2 is a careful,<br />

methodical reinvention of a mature,<br />

comprehensive framework. So Angular<br />

is less likely to churn in painful ways<br />

after release. And as a full framework,<br />

when you choose Angular, you can<br />

trust a single team to make careful<br />

decisions about the future. In React,<br />

it’s your responsibility to herd a bunch<br />

of disparate, fast-moving, open-source<br />

libraries into a comprehensive whole<br />

that plays well together. It’s time-consuming,<br />

frustrating, and a never-ending<br />

job.<br />

Broad tooling support<br />

As you’ll see below, I consider React’s<br />

JSX a big win. However, you need to<br />

select tooling that supports JSX. React<br />

has become so popular that tooling<br />

support is rarely a problem today, but<br />

new tooling such as IDEs and linters<br />

are unlikely to support JSX on day one.<br />

Angular 2’s templates store markup in<br />

a string or in separate HTML files, so it<br />

doesn’t require special tooling support<br />

(though it appears tooling to intelligently<br />

parse Angular’s string templates is<br />

on the way).<br />

Web component friendly<br />

Angular 2’s design embraces the web<br />

component’s standard. Sheesh, I’m<br />

embarrassed I forgot to mention this<br />

initially — I recently published a course<br />

on web components! In short, the<br />

components that you build in Angular<br />

2 should be much easier to convert<br />

into plain, native web components than<br />

React’s components. Sure, browser<br />

support is still weak, but this could be a<br />

big win in the long-term.<br />

Angular’s approach comes with<br />

its own set of gotchas, which is a good<br />

segue for discussing React’s advantages…<br />

React advantages<br />

Alright, let’s consider what sets React<br />

apart.<br />

JSX<br />

JSX is an HTML-like syntax that<br />

compiles down to JavaScript. Markup<br />

and code are composed in the same file.<br />

This means code completion gives you<br />

a hand as you type references to your<br />

component’s functions and variables.<br />

In contrast, Angular’s string-based templates<br />

come with the usual downsides:<br />

No code coloring in many editors,<br />

limited code completion support, and<br />

run-time failures. You’d normally<br />

expect poor error messaging as well,<br />

but the Angular team created their own<br />

HTML parser to fix that. (Bravo!)<br />

If you don’t like Angular stringbased<br />

templates, you can move the<br />

templates to a separate file, but then<br />

you’re back to what I call “the old<br />

days:” wiring the two files together in<br />

your head, with no code completion<br />

support or compile-time checking to<br />

assist. That doesn’t seem like a big<br />

deal until you’ve enjoyed life in React.<br />

Composing components in a single<br />

compile-time checked file is one of the<br />

big reasons JSX is so special.<br />

For more on why JSX is such a big<br />

win, see JSX: The Other Side of the<br />

Coin.<br />

React fails fast and explicitly<br />

When you make a typo in React’s JSX,<br />

it won’t compile. That’s a beautiful<br />

thing. It means you know immediately<br />

exactly which line has an error. It tells<br />

you immediately when you forget to<br />

close a tag or reference a property that<br />

doesn’t exist. In fact, the JSX compiler<br />

specifies the line number where the<br />

typo occurred. This behavior radically<br />

speeds development.<br />

In contrast, when you mistype a<br />

variable reference in Angular 2, nothing<br />

happens at all. Angular 2 fails quietly<br />

at run time instead of compile-time. It<br />

fails slowly. I load the app and wonder<br />

why my data isn’t displaying. Not fun.<br />

React is JavaScript-centric<br />

Here it is. This is the fundamental<br />

difference between React and Angular.<br />

Unfortunately, Angular 2 remains HT-<br />

ML-centric rather than JavaScript-centric.<br />

Angular 2 failed to solve its most<br />

fundamental design problem:<br />

Angular 2 continues to put “JS”<br />

into HTML. React puts “HTML”<br />

into JS.<br />

I can’t emphasize the impact of this<br />

schism enough. It fundamentally<br />

impacts the development experience.<br />

Angular’s HTML-centric design<br />

remains its greatest weakness. As I<br />

cover in “JSX: The Other Side of the<br />

Coin”, JavaScript is far more powerful<br />

than HTML. Thus, it’s more logical to<br />

enhance JavaScript to support markup<br />

than to enhance HTML to support<br />

logic. HTML and JavaScript need<br />

to be glued together somehow, and<br />

React’s JavaScript-centric approach<br />

is fundamentally superior to Angular,<br />

Ember, and Knockout’s HTML-centric<br />

approach.<br />

Here’s why…<br />

React’s JavaScript-centric design =<br />

Simplicity<br />

Angular 2 continues Angular 1’s<br />

approach of trying to make HTML<br />

more powerful. So you have to utilize<br />

hacker bits<br />

23


Angular 2's unique syntax for simple<br />

tasks like looping and conditionals. For<br />

example, Angular 2 offers both one and<br />

two way binding via two syntaxes that<br />

are unfortunately quite different:<br />

{{myVar}} //One-way binding<br />

ngModel="myVar" //Two-way binding<br />

In React, binding markup doesn’t<br />

change based on this decision (it’s handled<br />

elsewhere, as I’d argue it should<br />

be). In either case, it looks like this:<br />

{myVar}<br />

Angular 2 supports inline master templates<br />

using this syntax:<br />

<br />

<br />

{{hero.name}}<br />

<br />

<br />

The above snippet loops over an array<br />

of heroes. I have multiple concerns:<br />

• Declaring a “master template” via<br />

a proceeding asterisk is cryptic.<br />

• The pound sign in front of hero<br />

declares a local template variable.<br />

This key concept looks like needless<br />

noise (if preferred, you can use<br />

var).<br />

• The ngFor adds looping semantics<br />

to HTML via an Angular-specific<br />

attribute.<br />

Contrast Angular 2’s syntax above with<br />

React’s pure JS*: (admittedly the key<br />

property below is React-specific)<br />

<br />

{ heroes.map(hero =><br />

{hero.<br />

name}<br />

)}<br />

<br />

Since JS supports looping natively,<br />

React’s JSX can simply leverage all<br />

the power of JS for such things and do<br />

much more with map, filter, etc.<br />

Just read the Angular 2 Cheat<br />

Sheet. That’s not HTML. That’s not<br />

JavaScript. It’s Angular.<br />

To read Angular: Learn a long<br />

list of Angular-specific syntax.<br />

To read React: Learn JavaScript.<br />

React is unique in its syntactic and<br />

conceptual simplicity. Consider iterating<br />

in today’s popular JS frameworks/<br />

libraries:<br />

Ember: {{# each}}<br />

Angular 1: ng-repeat<br />

Angular 2: ngFor<br />

Knockout: data-bind=”foreach”<br />

React: JUST USE JS. :)<br />

All except React use framework<br />

specific replacements for something<br />

that is native and trivial in JavaScript:<br />

Contrasting how Angular 2 and React handle a missing closing tag<br />

24 hacker bits


a loop. That’s the beauty of React. It<br />

embraces the power of JavaScript to<br />

handle markup, so no odd new syntax<br />

is required.<br />

Angular 2’s syntactic oddities<br />

continue with click binding:<br />

(click)=”onSelect(hero)"<br />

In contrast, React again uses plain ‘ol<br />

JavaScript:<br />

onClick={this.onSelect.bind(this,<br />

hero)}<br />

And since React includes a synthetic<br />

event system (as does Angular 2), you<br />

don’t have to worry about the performance<br />

implications of declaring event<br />

handlers inline like this.<br />

Why fill your head with a framework’s<br />

unique syntax if you don’t have<br />

to? Why not simply embrace the power<br />

of JS?<br />

Luxurious development experience<br />

JSX’s code completion support,<br />

compile-time checks, and rich error<br />

messaging already create an excellent<br />

development experience that saves both<br />

typing and time. But combine all that<br />

with hot reloading with time travel and<br />

you have a rapid development experience<br />

like no other.<br />

Size concerns<br />

Here’s the size of notable frameworks/<br />

libraries, minified (source):<br />

Angular 2: 566k (766k with RxJS)<br />

Ember: 435k<br />

Angular 1: 143k<br />

React + Redux: 139k<br />

Edit: Sorry, I had incorrect numbers<br />

earlier that were for simple ToDoMVC<br />

apps instead of the raw frameworks.<br />

Also, the Angular 2 number is expected<br />

to drop for the final release. The sizes<br />

listed are for the framework, minified,<br />

in the browser (no gzip is factored in<br />

here).<br />

To make a real comparison, I built<br />

Angular 2’s Tour of Heroes app in both<br />

Angular 2 and React (I used the new<br />

React Slingshot starter kit). The result?<br />

Angular 2: 764k minified<br />

React + Redux: 151k minified<br />

So Angular 2 is over three times the<br />

size of a React + Redux app of comparable<br />

simplicity. (Again, Angular 2 is<br />

expected to lose some weight before<br />

the final release.<br />

Now that said, I admit that concerns<br />

about the size of frameworks may<br />

be overblown:<br />

Large apps tend to have a<br />

minimum of several hundred<br />

kilobytes of code — often<br />

more — whether they’re built<br />

with a framework or not. Developers<br />

need abstractions to build<br />

complex software, and whether<br />

they come from a framework or<br />

are hand-written, they negatively<br />

impact the performance of apps.<br />

Even if you were to eliminate<br />

frameworks entirely, many apps<br />

would still have hundreds of<br />

kilobytes of JavaScript. — Tom<br />

Dale in JavaScript Frameworks<br />

and Mobile Performance<br />

Tom is right. Frameworks like<br />

Angular and Ember are bigger<br />

because they offer many more<br />

features out of the box.<br />

However, my concern is this: many<br />

apps don’t need everything these large<br />

frameworks put in the box. In a world<br />

that’s increasingly embracing microservices,<br />

microapps, and single-responsibility<br />

packages, React gives you the<br />

power to “right-size” your application<br />

by carefully selecting only what is necessary.<br />

In a world with over 200,000<br />

npm modules, that’s a powerful place<br />

to be.<br />

React embraces the Unix Philosophy<br />

React is a library. It’s precisely the<br />

opposite philosophy of large, comprehensive<br />

frameworks like Angular<br />

and Ember. So when you select React,<br />

you’re free to choose modern best-ofbreed<br />

libraries that solve your problem<br />

best. JavaScript moves fast, and React<br />

allows you to swap out small pieces<br />

of your application for better libraries<br />

instead of waiting around and hoping<br />

your framework will innovate.<br />

Unix has stood the test of time.<br />

Here’s why:<br />

The philosophy of small, composable,<br />

single-purpose tools<br />

never goes out of style.<br />

React is a focused, composable,<br />

single-purpose tool used by many of<br />

the largest websites in the world. That<br />

bodes well for its future (That said, Angular<br />

is used by many big names too).<br />

Showdown summary<br />

Angular 2 is a huge improvement over<br />

version 1. The new component model is<br />

simpler to grasp than v1’s directives, it<br />

supports isomorphic/universal rendering,<br />

and it uses a virtual DOM offering<br />

3–10x improvements in performance.<br />

These changes make Angular 2 very<br />

competitive with React. There’s no<br />

denying that its full-featured, opinionated<br />

nature offers some clear benefits<br />

by reducing “JavaScript fatigue”.<br />

However, Angular 2’s size and syntax<br />

give me pause. Angular’s commitment<br />

to HTML-centric design makes it<br />

complex compared to React’s simpler<br />

JavaScript-centric model. In React, you<br />

don’t learn framework-specific HTML<br />

shims like ngWhatever. You spend your<br />

time writing plain ‘ol JavaScript. That’s<br />

the future I believe in. •<br />

Reprinted with permission of the original author. First appeared at medium.freecodecamp.com.<br />

hacker bits<br />

25


OPINION<br />

Apple’s declining<br />

software quality<br />

By PAUL JONES<br />

26 hacker bits


“ Software quality is a nebulous and<br />

divisive topic. There are many<br />

parameters to software quality<br />

– reliability, speed, user experience,<br />

design, discoverability, and more – and<br />

a move towards any of these virtues<br />

leads to sacrifices in others, especially<br />

on a limited time schedule.<br />

Additionally, a number of forces<br />

influence software quality over time,<br />

like accommodating for different use<br />

cases, changes in platform, changes in<br />

hardware, changes in design preferences,<br />

changes in market, changes in expectations,<br />

and more. Finally, software<br />

is not like digging a hole, say, where<br />

more people really can dig a hole faster<br />

than fewer people: in fact, more people<br />

can often slow down a software project.<br />

Nobody knows this better than<br />

the technology titans of today: Apple,<br />

Google, Facebook, Amazon, Microsoft,<br />

IBM and Oracle have all experienced<br />

unanticipated software problems, regressions<br />

and high profile bugs. These<br />

are organizations with thousands of<br />

programmers writing and maintaining<br />

millions of lines of code for billions of<br />

devices. And these devices are machines<br />

which require perfection: one<br />

slight ambiguity of intent, any minor<br />

breach of contract, any single unexpected<br />

0 where there should be 1 or vice<br />

versa has the capability the bring down<br />

the whole system. In fact, it often does.<br />

Countless kernel panics, stack<br />

overflow errors, null pointer exceptions,<br />

and memory leaks are plaguing<br />

poor users, tired system administrators<br />

and overworked programmers right<br />

now. Machines are fast, but they can be<br />

awfully dumb.<br />

...it’s time to admit that Apple<br />

has flown too close to the sun.<br />

And no company is feeling the<br />

pain of software’s nebulous nature and<br />

hardware’s mindless computing more<br />

than Apple right now. The underdog<br />

that many loyal fans rooted for is now<br />

the world’s (perhaps previous) most<br />

valuable company.<br />

With that, comes insanely high<br />

expectations: they need to grow the<br />

world’s biggest company every quarter<br />

to keep Wall Street happy, and even<br />

harder, they have to keep those nerds<br />

that kept them alive through the hard<br />

times happy too. And with release<br />

after release of the most revolutionary<br />

operating system ever, it’s tempting to<br />

picture Apple like an actual Titan, in<br />

particular Atlas, holding the world upon<br />

his shoulders. But it seems more and<br />

more every day that another Greek tale<br />

is more fitting: it’s time to admit that<br />

Apple has flown too close to the sun.<br />

Walt Mossberg, technology journalism’s<br />

elder statesman, has this to say<br />

about Apple’s software quality:<br />

In the last couple of years,<br />

however, I’ve noticed a gradual<br />

degradation in the quality and<br />

reliability of Apple’s core apps,<br />

on both the mobile iOS operating<br />

system and its Mac OS X<br />

platform. It’s almost as if the<br />

tech giant has taken its eye off<br />

the ball when it comes to these<br />

core software products, while<br />

it pursues big new dreams, like<br />

smartwatches and cars.<br />

On OS X this is especially true:<br />

OpenGL implementation has fallen<br />

behind the competition, the filesystem<br />

desperately needs updating, the SDK<br />

has needed modernizing for years,<br />

networking and cryptography have seen<br />

major gaffes. And that’s with regards to<br />

the under-the-hood details, the applications<br />

are easier targets: it’s tragic that<br />

Aperture and iPhoto were axed in favor<br />

of the horrifically bad Photos app (that<br />

looks like some Frankenstein “iOS X”<br />

app); the entire industry has left Final<br />

Cut Pro X; I dare not plug my iPhone<br />

in to my laptop for fear of what it might<br />

do; the Mac App Store is the antitheses<br />

of native application development<br />

(again a Frankenstein of a web/native<br />

app); and iCloud nee MobileMe nee<br />

iTools has been an unreliable and slow<br />

mess since day one.<br />

This isn’t the first time that a prominent<br />

member of the Apple community<br />

has criticized Apple’s software quality.<br />

Here’s Marco Arment from January of<br />

2015:<br />

Apple’s hardware today is amazing<br />

— it has never been better.<br />

But the software quality has fallen<br />

so much in the last few years<br />

that I’m deeply concerned for its<br />

future. I’m typing this on a computer<br />

whose existence I didn’t<br />

even think would be possible yet,<br />

but it runs an OS with embarrassing<br />

bugs and fundamental<br />

regressions. Just a few years<br />

ago, we would have relentlessly<br />

made fun of Windows users for<br />

these same bugs on their inferior<br />

OS, but we can’t talk anymore.<br />

This is still as true today as it was<br />

last year. Macs and iPhones have got-<br />

hacker bits<br />

27


ten thinner, more beautiful, and more<br />

powerful; the Apple Watch and the new<br />

Apple TV are magnificent additions to<br />

the product line up. But I’d speculate<br />

that part of the problem Apple is having<br />

is that if it took 1,000 engineers to<br />

write software for Mac when that was<br />

the only product, it doesn’t necessarily<br />

take 4,000 people to write software for<br />

four product lines. In fact, 10,000 of the<br />

same grade of engineers might not even<br />

do it, especially without proper management<br />

and unified goals. Apple may<br />

not have listened to rockstar developer<br />

Marco Arment, but Walt Mossberg will<br />

definitely get their attention. Here’s an<br />

“<br />

anecdote about Steve Jobs from the last<br />

time that Mossberg complained about<br />

Apple’s software quality:<br />

In Fortune’s story, Lashinsky<br />

says Steve Jobs summoned<br />

the entire MobileMe team for<br />

a meeting at the company’s<br />

on-campus Town Hall, accusing<br />

everyone of “tarnishing Apple’s<br />

reputation.” He told the members<br />

of the team they “should<br />

hate each other for having let<br />

each other down”, and went on<br />

to name new executives on the<br />

spot to run the MobileMe team.<br />

A few excerpts from the article.<br />

“Can anyone tell me what<br />

MobileMe is supposed to do?”<br />

Having received a satisfactory<br />

answer, he continues, “So why<br />

the fuck doesn’t it do that?”<br />

Jobs was also particularly angry<br />

about the Wall Street Journal’s<br />

Walt Mossberg not liking MobileMe:<br />

“Mossberg, our friend, is no<br />

longer writing good things about<br />

us.”<br />

It really is time for Tim Cook to<br />

take action as drastic as this regarding<br />

software quality on Apple’s existing<br />

platforms. What worries me is that<br />

the AAPL stock ticker and Apple the<br />

company are in a (self-driving) crash<br />

course with one another. AAPL needs<br />

to launch new products to drive growth<br />

and Apple needs to improve the products<br />

that have already shipped. The<br />

most valuable asset that Apple owns is<br />

their brand, and that’s the brand that’ll<br />

drive sales of any car that may or may<br />

not be in development. If that brand<br />

name is tarnished by regressions and<br />

performance problems, what consumer<br />

would buy a car from the brand? In<br />

fact, anecdotally, talking to my friends,<br />

the Apple Car already has an uphill<br />

battle with the kerfuffle surrounding the<br />

Maps launch.<br />

Jim Dalrymple, in response to<br />

Mossberg, writes:<br />

I understand that Apple has a lot<br />

of balls in the air, but they have<br />

clearly taken their eye off some<br />

of them. There is absolutely no<br />

doubt that Apple Music is getting<br />

better with each update to the<br />

app, but what we have now is<br />

more of a 1.0 version than what<br />

we received last year.<br />

John Gruber, in response to Dalrymple:<br />

Maybe we expect too much from<br />

Apple’s software. But Apple’s<br />

hardware doesn’t have little<br />

problems like this.<br />

The best thing for Apple to do is<br />

to re-take their position as a leader of<br />

software quality before it’s too late:<br />

consumers know that Apple’s hardware<br />

is the very best, but more and more<br />

they’re using apps made by Google<br />

and Microsoft and Facebook. If this<br />

trend doesn’t turn around, Apple will<br />

find their breakout product and all of its<br />

Apple can do this. It’s not too late.<br />

growth will be owned by competitors.<br />

And when the time comes to<br />

launch their car, they’ll find that loyal<br />

fans and everyday consumers will have<br />

lost trust in the brand. Having said that,<br />

I’m still a Mac user at home and at<br />

work, my iPhone is a wonderful device<br />

that enriches my life, and I’m still<br />

finding new ways to make use of Apple<br />

Watch. And to give credit where credit<br />

is due: Logic Pro X has improved a lot<br />

recently, and Music Memos is a welcome<br />

addition to Apple’s music line up.<br />

I even use Apple Maps. Apple can do<br />

this. It’s not too late. But for the sake<br />

of all us poor users, and Apple’s tired<br />

system administrators and overworked<br />

programmers, I hope they had started 6<br />

months ago. •<br />

Reprinted with permission of the original author. First appeared at sudophilosophical.com.<br />

28 hacker bits


PROGRAMMING<br />

9 things every React.js<br />

beginner should know<br />

By CAM JACKSON<br />

I've been using React.js for about 6 months now. In the<br />

grand scheme of things that's not very long at all, but<br />

in the ever-churning world of JavaScript frameworks,<br />

that just about qualifies you as a bearded elder! I've helped<br />

out a few people lately with React starter tips, so I thought<br />

it would be a good idea to write some of them up here to<br />

share more broadly. These are all either things that I wish<br />

I'd known when I started out, or things that really helped me<br />

'get' React.<br />

I'm going to assume that you know the absolute basics;<br />

if the words component, props, or state are unfamiliar to you,<br />

then you might want to read the official Getting started or<br />

Tutorial pages. I'm also going to use JSX, because it's a much<br />

more succinct and expressive syntax for writing components.<br />

1. It's just a view library<br />

Let's get the basics out of the way. React is not another MVC<br />

framework, or any other kind of framework. It's just a library<br />

for rendering your views. If you're coming from the MVC<br />

world, you need to realise that React is just the 'V', part of<br />

the equation, and you need to look elsewhere when it comes<br />

to defining your 'M' and 'C', otherwise you're going to end up<br />

with some really yucky React code. More on that later.<br />

2. Keep your components small<br />

This might seem like an obvious one, but it's worth calling<br />

out. Every good developer knows that small classes/modules/<br />

whatever are easier to understand, test, and maintain, and<br />

the same is true of React components. My mistake when<br />

starting out with React was underestimating just how small<br />

my components should be. Of course, the exact size will<br />

depend upon many different factors (including you and your<br />

team's personal preference!), but in general my advice would<br />

be to make your components significantly smaller than you<br />

think they need to be. As an example, here is the component<br />

that shows my latest blog entries on the home page of my<br />

website:<br />

const LatestPostsComponent = props => (<br />

<br />

Latest posts<br />

<br />

{ props.posts.map(post => ) }<br />

);<br />

<br />

<br />

The component itself is a , with only 2 s<br />

inside it. The first one has a heading, and second one just<br />

maps over some data, rendering a for each<br />

element. That last part, extracting the as its<br />

own component, is the important bit. I think this is a good<br />

size for a component.<br />

3. Write functional components<br />

Previously there were two choices for defining React components,<br />

the first being React.createClass():<br />

const MyComponent = React.createClass({<br />

render: function() {<br />

}<br />

});<br />

return ;<br />

... and the other being ES6 classes:<br />

class MyComponent extends React.Component {<br />

}<br />

render() {<br />

}<br />

return ;<br />

hacker bits<br />

29


“<br />

React 0.14 introduced a new syntax for defining components,<br />

as functions of props:<br />

const MyComponent = props => (<br />

<br />

);<br />

This is by far my favourite method for defining React components.<br />

Apart from the more concise syntax, this approach<br />

can really help make it obvious when a component needs to<br />

be split up. Let's revisit the earlier example, and imagine that<br />

we hadn't split it up yet:<br />

class LatestPostsComponent extends React.Component<br />

{<br />

render() {<br />

}<br />

const postPreviews = renderPostPreviews();<br />

return (<br />

);<br />

<br />

Latest posts<br />

<br />

{ postPreviews }<br />

<br />

<br />

renderPostPreviews() {<br />

return this.props.posts.map(post => this.<br />

renderPostPreview(post));<br />

}<br />

renderPostPreview(post) {<br />

return (<br />

<br />

title}<br />

{post.<br />

{post.posted}<br />

<br />

more...<br />

React is...just a library for<br />

rendering your views.<br />

{post.blurb}<br />

Read<br />

}<br />

}<br />

);<br />

<br />

<br />

This class isn't too bad, as far as classes go. We've already<br />

extracted a couple of methods out of the render method<br />

to keep things small and well-named. And we've encapsulated<br />

the idea of rendering the latest post previews pretty well.<br />

Let's rewrite the same code using the functional syntax:<br />

const LatestPostsComponent = props => {<br />

const postPreviews = renderPostPreviews(props.<br />

posts);<br />

};<br />

return (<br />

);<br />

<br />

Latest posts<br />

<br />

{ postPreviews }<br />

<br />

<br />

const renderPostPreviews = posts => (<br />

);<br />

posts.map(post => this.renderPostPreview(post))<br />

const renderPostPreview = post => (<br />

<br />

{post.<br />

title}<br />

a><br />

);<br />

{post.posted}<br />

<br />

{post.blurb}<br />

Read more...


ever, for me, that makes a big difference. In the class-based<br />

example, my eyes see class LatestPostsComponent {, and<br />

naturally scan all the way down to the closing curly bracket,<br />

concluding "that's the end of the class, and so the end of<br />

the component". By comparison, when I read the functional<br />

component, I see const LatestPostsComponent = props<br />

=> {, and scan only to the end of that function. "There's the<br />

end of the function, and so the end of the component", I think<br />

to myself. "But wait, what's all this other code sitting outside<br />

of my component, in the same module? Aha! It's another<br />

function that takes data and renders a view! I can extract that<br />

out into a component all of it's own!"<br />

Which is a very long-winded way of saying that functional<br />

components help us identify ways to follow point #2.<br />

There are also optimisations coming to React in the future,<br />

which will make functional components more efficient<br />

than class-based ones. (Update: It turns out that the performance<br />

implications of functional components are much<br />

more complicated than I realised. I still recommend writing<br />

functional components by default, but if performance is a big<br />

concern, then you should read and understand this and this,<br />

and figure out what works best for you.)<br />

It's important to note that functional components have<br />

a few 'limitations', which I consider to be their greatest<br />

strengths. The first is that a functional component cannot<br />

have a ref assigned to it. While a ref can be a convenient<br />

way for a component to 'look up' it's children and communicate<br />

with them, my feeling is that this is The Wrong Way<br />

to write React. refs encourage a very imperative, almost<br />

jquery-like way of writing components, taking us away from<br />

the functional, one-way data flow philosophy for which we<br />

chose React in the first place!<br />

The other big difference is that functional components<br />

cannot have state attached to them, which is also a huge<br />

advantage, because my next tip is to...<br />

4. Write stateless components<br />

I would have to say that by far, the vast, vast majority of pain<br />

that I've felt when writing React-based apps, has been caused<br />

by components that have too much state.<br />

State makes components difficult to test<br />

There's practically nothing easier to test than pure, data-in<br />

data-out functions, so why would we throw away the opportunity<br />

to define our components in such a way by adding<br />

state to them? When testing stateful components, now we<br />

need to get our components into "the right state" in order<br />

to test their behaviour. We also need to come up with all of<br />

the various combinations of state (which the component can<br />

mutate at any time), and props (which the component has no<br />

control over), and figure out which ones to test, and how to<br />

do so. When components are just functions of input props,<br />

testing is a lot easier. (More on testing later.)<br />

State makes components difficult to reason about<br />

When reading the code for a very stateful component, you<br />

have to work a lot harder, mentally, to keep track of everything<br />

that's going on. Questions like "Has that state been<br />

initialised yet?", "What happens if I change this state here?",<br />

"How many other places change this state", "Is there a race<br />

condition on this state?", to mention a few, all become very<br />

common. Tracing through stateful components to figure out<br />

how they behave becomes very painful.<br />

State makes it too easy to put business logic in the<br />

component<br />

Searching through components to determine behaviour is not<br />

really something we should be doing anyway. Remember,<br />

React is a view library, so while render logic in the components<br />

is OK, business logic is a massive code smell. But<br />

when so much of your application's state is right there in the<br />

component, easily accessible by this.state, it can become<br />

really tempting to start putting things like calculations or<br />

validation into the component, where it does not belong. Revisiting<br />

my earlier point, this makes testing that much harder<br />

- you can't test render logic without the business logic getting<br />

in the way, and vice versa!<br />

State makes it difficult to share information to other parts<br />

of the app<br />

When a component owns a piece of state, it's easy to pass it<br />

further down the component hierarchy, but any other direction<br />

is tricky.<br />

“<br />

React is a view library...<br />

while render logic in the components is OK,<br />

business logic is a massive code smell.<br />

hacker bits<br />

31


“<br />

Of course, sometimes it makes sense for a particular<br />

component to totally own a particular piece of state. In which<br />

case, fine, go ahead use this.setState. It's a legitimate part<br />

of the React component API, and I don't want to give the<br />

impression that it should be off limits. For example, if a user<br />

is typing into a field, it might not make sense to expose every<br />

keypress to the whole app, and so the field may track its own<br />

intermediate state until a blur event happens, whereupon<br />

the final input value is sent outwards to become state stored<br />

somewhere else. This scenario was mentioned to me by a<br />

colleague recently, and I think it's a great example.<br />

Just be very conscious of every time you add state to a<br />

component. Once you start, it can become very easy to add<br />

'just one more thing', and things get out of control before you<br />

know it!<br />

propTypes add a lot of safety...<br />

frankly I see no reason not to use them<br />

all the time.<br />

5. Use Redux.js<br />

In point #1, I said that React is just for views. The obvious<br />

question then is, "Where do I put all my state and logic?" I'm<br />

glad you asked!<br />

You may already be aware of Flux, which is a style/pattern/architecture<br />

for designing web applications, most commonly<br />

ones that use React for rendering. There are several<br />

frameworks out there that implement the ideas of Flux, but<br />

without a doubt the one that I recommend is Redux.js*.<br />

I'm thinking of writing a whole separate blog post on the<br />

features and merits of Redux, but for now I'll just recommend<br />

you read through the official tutorial at the above link,<br />

and provide this very brief description of how Redux works:<br />

• Components are given callback functions as props,<br />

which they call when a UI event happens.<br />

• Those callbacks create and dispatch actions based on<br />

the event.<br />

• Reducers process the actions, computing the new state.<br />

• The new state of the whole application goes into a single<br />

store.<br />

• Components receive the new state as props and re-render<br />

themselves where needed.<br />

Most of the above concepts are not unique to Redux, but<br />

Redux implements them in a very clean and simple way, with<br />

a tiny API. Having switched a decent sized project over from<br />

Alt.js to Redux, some of the biggest benefits I've found are:<br />

• The reducers are pure functions, which simply do<br />

oldState + action = newState. Each reducer computes<br />

a separate piece of state, which is then all composed<br />

together to form the whole application. This<br />

makes all your business logic and state transitions really<br />

easy to test.<br />

• The API is smaller, simpler, and better documented. I've<br />

found it much quicker and easier to learn all of the concepts,<br />

and therefore much easier to understand the flow<br />

of actions and information in my own projects.<br />

• If you use it the recommended way, only a very small<br />

number of components will depend upon Redux; all<br />

the other components just receive state and callbacks<br />

as props. This keeps the components very simple, and<br />

reduces framework lock-in.<br />

There are a few other libraries that complement Redux extremely<br />

well, which I also recommend you use:<br />

• Immutable.js - Immutable data structures for JavaScript!<br />

Store your state in these, in order to make sure it isn't<br />

mutated where it shouldn't be, and to enforce reducer<br />

purity.<br />

• redux-thunk - This is used for when your actions need<br />

to have a side effect other than updating the application<br />

state. For example, calling a REST API, or setting<br />

routes, or even dispatching other actions.<br />

• reselect - Use this for composable, lazily-evaluated,<br />

views into your state. For example, for a particular component<br />

you might want to:<br />

––<br />

Inject only the relevant part of the global state<br />

tree, rather than the whole thing.<br />

––<br />

Inject extra derived data, like totals or validation<br />

state, without putting it all in the store.<br />

You don't necessarily need all of these from day one. I would<br />

* Depending on who you ask, Redux may or may not be 'true' Flux. Personally I feel that it's aligned well-enough with the core ideas to call it a Flux<br />

framework, but the argument is a semantic one anyway.<br />

32 hacker bits


add Redux and Immutable.js as soon you have any state,<br />

reselect as soon you have derived state, and redux-thunk as<br />

soon as you have routing or asynchronous actions. Adding<br />

them sooner rather than later will save you the effort of retro-fitting<br />

them in later on.<br />

beforeAll(() => {<br />

console.error = error => {<br />

throw new Error(error);<br />

};<br />

});<br />

6. Always use propTypes<br />

propTypes offer us a really easy way to add a bit more type<br />

safety to our components. They look like this:<br />

const ListOfNumbers = props => (<br />

);<br />

<br />

{<br />

}<br />

props.numbers.map(number => (<br />

)<br />

<br />

{number})<br />

ListOfNumbers.propTypes = {<br />

className: React.PropTypes.string.isRequired,<br />

numbers: React.PropTypes.arrayOf(React.PropTypes.<br />

number)<br />

};<br />

When in development (not production), if any component<br />

is not given a required prop, or is given the wrong type for<br />

one of its props, then React will log an error to let you know.<br />

This has several benefits:<br />

• It can catch bugs early, by preventing silly mistakes.<br />

• If you use isRequired, then you don't need to check for<br />

undefined or null as often.<br />

• It acts as documentation, saving readers from having to<br />

search through a component to find all the props that it<br />

needs.<br />

The above list looks a bit like one you might see from<br />

someone advocating for static typing over dynamic typing.<br />

Personally, I usually prefer dynamic typing for the ease and<br />

speed of development it provides, but I find that propTypes<br />

add a lot of safety to my React components, without making<br />

things any more difficult. Frankly I see no reason not to use<br />

them all the time.<br />

One final tip is to make your tests fail on any propType<br />

errors. The following is a bit of a blunt instrument, but it's<br />

simple and it works:<br />

7. Use shallow rendering<br />

Testing React components is still a bit of a tricky topic. Not<br />

because it's hard, but because it's still an evolving area, and<br />

no single approach has emerged as the 'best' one yet. At the<br />

moment, my go-to method is to use shallow rendering and<br />

prop assertions.<br />

Shallow rendering is nice, because it allows you to<br />

render a single component completely, but without delving<br />

into any of its child components to render those. Instead, the<br />

resulting object will tell you things like the type and props of<br />

the children. This gives us good isolation, allowing testing of<br />

a single component at a time.<br />

There are three types of component unit tests I find myself<br />

most commonly writing:<br />

Render logic<br />

Imagine a component that should conditionally display either<br />

an image, or a loading icon:<br />

const Image = props => {<br />

};<br />

if (props.loading) {<br />

}<br />

return ;<br />

return ;<br />

We might test it like this:<br />

describe('Image', () => {<br />

it('renders a loading icon when the image is<br />

loading', () => {<br />

const image = shallowRender();<br />

{<br />

});<br />

expect(image.type).toEqual(LoadingIcon);<br />

it('renders the image once it has loaded', () =><br />

const image = shallowRender();<br />

hacker bits<br />

33


“<br />

expect(image.type).toEqual('img');<br />

});<br />

});<br />

Easy! I should point out that the API for shallow rendering<br />

is slightly more complicated than what I've shown.<br />

The shallowRender function used above is our own helper,<br />

which wraps the real API to make it easier to use.<br />

Revisiting our ListOfNumbers component above, here is<br />

how we might test that the map is done correctly:<br />

describe('ListOfNumbers', () => {<br />

it('renders an item for each provided number', ()<br />

=> {<br />

At the moment, my go-to method<br />

is to use shallow rendering<br />

and prop assertions.<br />

const listOfNumbers =<br />

shallowRender();<br />

describe('TextWithArrayOfClassNames', () => {<br />

it('turns the array into a space-separated<br />

string', () => {<br />

const text = 'Hello, world!';<br />

const classNames = ['red', 'bold', 'floatright'];<br />

const textWithArrayOfClassNames =<br />

shallowRender();<br />

const childClassNames =<br />

textWithArrayOfClassNames.props.children.props.<br />

className;<br />

expect(childClassNames).toEqual('red bold floatright');<br />

});<br />

});<br />

expect(listOfNumbers.props.children.length).<br />

toEqual(4);<br />

});<br />

});<br />

Prop transformations<br />

In the last example, we dug into the children of the component<br />

being tested, to make sure that they were rendered<br />

correctly. We can extend this by asserting that not only are<br />

the children there, but that they were given the correct props.<br />

This is particulary useful when a component does some<br />

transformation on its props, before passing them on. For<br />

example, the following component takes CSS class names<br />

as an array of strings, and passes them down as a single,<br />

space-separated string:<br />

const TextWithArrayOfClassNames = props => (<br />

);<br />

<br />

<br />

{props.text}<br />

<br />

<br />

One common criticism of this approach to testing is the<br />

proliferation of props.children.props.children... While<br />

it's not the prettiest code, personally I find that if I'm being<br />

annoyed by writing props.children too much in the one<br />

test, that's a sign that the component is too big, complex, or<br />

deeply nested, and should be split up.<br />

The other thing I often hear is that your tests become too<br />

dependant on the component's internal implementation, so<br />

that changing your DOM structure slightly causes all of your<br />

tests to break. This is definitely a fair criticism, and a brittle<br />

test suite is the last thing that anyone wants. The best way to<br />

manage this is to (wait for it) keep your components small<br />

and simple, which should limit the number of tests that break<br />

due to any one component changing.<br />

User interaction<br />

Of course, components are not just for display, they're also<br />

interactive:<br />

const RedInput = props => (<br />

/><br />

)<br />


Here's my favourite way to test these:<br />

describe('RedInput', () => {<br />

it('passes the event to the given callback when<br />

the value changes', () => {<br />

const callback = jasmine.createSpy();<br />

const redInput = shallowRender();<br />

redInput.props.onChange('an event!');<br />

expect(callback).toHaveBeenCalledWith('an<br />

event!');<br />

});<br />

});<br />

It's a bit of a trivial example, but hopefully you get the idea.<br />

Integration testing<br />

So far I've only covered unit testing components in isolation,<br />

but you're also going to want some higher level tests in order<br />

to ensure that your application connects up properly and<br />

actually works. I'm not going to go into too much detail here,<br />

but basically:<br />

1. Render your entire tree of components (instead of<br />

shallow rendering).<br />

2. Reach into the DOM (using the React TestUtils, or<br />

jQuery, etc) to find the elements you care about the<br />

most, and then:<br />

• Assert on their HTML attributes or contents, or<br />

• Simulate DOM events and then assert on the<br />

side effects (DOM or route changes, AJAX<br />

calls, etc).<br />

On TDD<br />

In general, I don't use TDD when writing React components.<br />

When working on a component, I often find myself<br />

churning its structure quite a bit, as I try to land on the simplest<br />

HTML and CSS that looks right in whatever browsers<br />

I need to support. And because my component unit testing<br />

approach tends to assert on the component structure, TDD<br />

would cause me to be constantly fixing my tests as I tweak<br />

the DOM, which seems like a waste of time.<br />

The other factor to this is that the components should be<br />

so simple that the advantages of test-first are diminished. All<br />

of the complex logic and transformations are pulled out into<br />

action creators and reducers, which is where I can (and do)<br />

reap the benefits of TDD.<br />

Which brings me to my final point about testing. In this<br />

whole section, I've been talking about testing the components,<br />

and that's because there's no special information needed<br />

for testing the rest of a Redux-based app. As a framework,<br />

Redux has very little 'magic' that goes on behind the scenes,<br />

which I find reduces the need for excessive mocking or other<br />

test boilerplate. Everything is just plain old functions (many<br />

of them pure), which is a real breath of fresh air when it<br />

comes to testing.<br />

8. Use JSX, ES6, Babel, Webpack, and<br />

NPM<br />

The only React-specific thing here is JSX. For me JSX is a<br />

no-brainer over manually calling React.createElement. The<br />

only disadvantage is that we add a small amount of buildtime<br />

complexity, which is easily solved with Babel.<br />

Once we've added Babel though, there's no reason not to<br />

go all out and use all the great ES6 features, like constants,<br />

arrow functions, default arguments, array and object destructuring,<br />

spread and rest operators, string interpolation, iterators<br />

and generators, a decent module system, etc. It really<br />

feels like JavaScript is beginning to 'grow up' as a language<br />

these days, as long as you're prepared to spend a little bit of<br />

time setting up the tools.<br />

We round things out with Webpack for bundling our<br />

code, and NPM for package management, and we're now<br />

fully JavaScript buzzword compliant :)<br />

9. Use the React and Redux dev tools<br />

Speaking of tooling, the development tools for React and<br />

Redux are pretty awesome. The React dev tools let you inspect<br />

the rendered tree of React elements, which is incredibly<br />

useful for seeing how things actually look in the browser.<br />

The Redux dev tools are even more impressive, letting you<br />

see every action that has happened, the state changes that<br />

they caused, and even giving you the ability to travel back<br />

in time! You can add it either as a dev dependency, or as a<br />

browser extension.<br />

You can also set up hot module replacement with webpack,<br />

so that your page updates as soon as you save your<br />

code - no browser refresh required. This makes the feedback<br />

loops a lot more efficient when tweaking your components<br />

and reducers.<br />

That's it!<br />

Hopefully that will give you a bit of a head-start on React,<br />

and help you avoid some of the more common mistakes.<br />

If you enjoyed this post, you might like to follow me on<br />

Twitter, or subscribe to my RSS feed.<br />

Thanks for reading! •<br />

Reprinted with permission of the original author. First appeared at camjackson.net.<br />

hacker bits<br />

35


OPINION<br />

Imagining your future<br />

projects is holding you back<br />

By JESSICA ABEL<br />

Do you have a big creative<br />

project in store? Do you lie<br />

awake sometimes, thinking<br />

about what might go into it, what the<br />

characters or environment might look<br />

like, how it will touch the audience in<br />

a whole new way? Do you imagine<br />

what it will feel like to have this project<br />

under your belt, and what kind of effect<br />

it will have on your life?<br />

Let me tell you about Forest Lords.<br />

Forest Lords is a series of ten<br />

fantasy novels, each a 1000-page brick,<br />

about the epic adventures of Greenleaf<br />

Barksley, elf proletarian, and his journeys<br />

to attain the Golden Leaf and save<br />

his homeland from the scourge of the<br />

Curse of the Titaness Denox.<br />

The thing is, none of this series<br />

exists—not even Forest Lords Volume<br />

One: The Elven Soul. There are binders<br />

and binders of “lore.” There are a hell<br />

of a lot of character designs (that look<br />

suspiciously similar to Elfquest characters).<br />

There is the vivid, lively picture<br />

the putative author has in his head of<br />

how it’s going to feel to write a fantasy<br />

series that has everyone panting for the<br />

next book or movie or TV show.*<br />

But there is no book. There is only<br />

Idea Debt.<br />

* As a matter of actual fact, there are no binders either. This concept was invented by Benjamin Frisch when he was a snotty teen to poke fun the massive<br />

Idea Debts being racked up by others he encountered in the comics scene.<br />

36 hacker bits


What is idea debt?<br />

I got this term from Kazu Kibuishi<br />

when I interviewed him for Out on the<br />

Wire episode 7: Dark Forest. His name<br />

for the concept was new to me, but it<br />

solved a huge problem: what to call this<br />

struggle with creative sunk costs that<br />

I understand all too intimately. Here’s<br />

Kazu:<br />

I try not to to look at what I’m<br />

going to do as this amazing<br />

great grand thing. I’m not just<br />

fulfilling some old promise that<br />

I made a long time ago. Now<br />

I’m actually solving problems<br />

in the moment, and that’s so<br />

much more exciting than than<br />

trying to fill years of what I like<br />

to call my “idea debt.” That’s<br />

when you have this dream of this<br />

awesome thing for years. You<br />

think, “Oh, I’m going to do this<br />

epic adventure. It’s going to be<br />

so great.” The truth is, no matter<br />

what you do, it will never be as<br />

great as it is in your mind, and<br />

so you’re really setting yourself<br />

up for failure.<br />

I like snowboarding, and I used<br />

to like hitting all the jumps.<br />

And when I would go down<br />

the mountain, I would notice a<br />

bunch of young snowboarders<br />

who were waiting at the top of<br />

the jumps.<br />

They may look like they’re waiting<br />

their turn. But in fact that<br />

they’re waiting there because<br />

they’re afraid to hit that jump.<br />

And what they don’t realize is<br />

that, over time they’re getting<br />

colder.<br />

The Idea Debt of having to make<br />

that jump, and land it, and be<br />

impressive, is getting greater<br />

because of the amount of time<br />

they’re investing, waiting there,<br />

getting colder, at the top of the<br />

hill.<br />

By the time they actually do it,<br />

they’re probably not going to<br />

fulfill that dream. So I learned to<br />

just hit the jump or pass it. Do it<br />

in the moment, or not at all.<br />

Idea Debt is when you spend too<br />

much time picturing what a project is<br />

going to be like, too much time thinking<br />

about how awesome it will be to<br />

have this thing done and in the world,<br />

too much time imagining how cool you<br />

will look, how in demand you’ll be,<br />

how much money you’ll make. And<br />

way too little time actually making the<br />

thing.<br />

If…<br />

• You tell 15 friends about your<br />

screenplay idea, but devote zero<br />

time in your week to facing the<br />

blank screen.<br />

• You buy a domain name, spend<br />

weeks or months researching and<br />

reading up on how to build a website,<br />

but you don’t actually install<br />

WordPress.<br />

• You have a drawer full of half-finished<br />

stories and novels and a todo<br />

list item every week that reads,<br />

“work on writing.”<br />

• You’ve read 15 free online guides<br />

to blogging, built three editorial<br />

calendars, have notes on a dozen<br />

posts, but you haven’t gone live<br />

with your blog.<br />

• You have “binders of lore” and no<br />

book.<br />

…you’re living with serious Idea Debt.<br />

I’ve seen so many students struggle<br />

for years with Idea Debt. Carrying<br />

that debt crippled them. They were<br />

“<br />

Idea Debt is when you spend<br />

too much time picturing<br />

what a project is going to be like...<br />

hacker bits<br />

37


...the only way I will ever find out<br />

whether my project represents<br />

Idea Debt or Idea Investment<br />

is if I create a plan<br />

that breaks down the project<br />

“into actionable steps...<br />

beholden to their 12-year-old selves,<br />

who had imagined their grown-up<br />

future selves as famous manga authors<br />

with 40-volume series under their belts.<br />

But they did not have the tools yet to<br />

actually make the work happen. And so<br />

they invested more and more into this<br />

grand idea, making it less and less likely<br />

that they’d ever be able to pay it off.<br />

They had binders of lore.<br />

If you recognize yourself, you are<br />

definitely not alone. There’s nothing<br />

crazy about having Idea Debt. It’s the<br />

most natural thing to result when you<br />

have big creative ideas, but no real plan<br />

for actually working towards making<br />

them happen.<br />

Even if you’re extremely productive,<br />

you can have Idea Debt. There are<br />

only so many hours in a week, and you<br />

have to make choices. But all of those<br />

undone things weigh us down, make it<br />

impossible to think clearly about what<br />

we should devote our time and energy<br />

to now.<br />

I carry a huge amount of Idea<br />

Debt. But I’m thinking it’s about time<br />

to dump it. So many of the projects on<br />

my “someday/maybe” list belong to<br />

other, earlier versions of me, not the me<br />

of today.<br />

• Screenplay of one of my books?<br />

2007. No one is asking for it, and<br />

I haven’t been in that headspace<br />

since at least 2009.<br />

• Ebook series of my unpublished<br />

YA novel? 2006. Does that mean<br />

I’d have to actually read it again?<br />

• Sequel in a series? 2009. After the<br />

first one didn’t work? Why would I<br />

do that to myself?<br />

• Literary graphic novel idea? That<br />

one has been hanging around since<br />

1998 or so.<br />

I do have a very large idea debt<br />

that I want to pay, however. I have a<br />

concept for a series of paintings that<br />

I’ve been mulling over for probably<br />

close to 10 years. I have no plan for<br />

showing, much less selling them. I<br />

just want to make them so I can see<br />

them. I can picture them so clearly. I’ve<br />

thought about color, shape, size, even<br />

where I’ll hang them in my house. That<br />

I am not currently living in.<br />

I’m not in a position right now to<br />

start on something like that (my paint<br />

is in that same house in Brooklyn). I<br />

haven’t tested to see if this work will<br />

actually be exciting and satisfying<br />

to me. It might be pure Idea Debt.<br />

But perhaps, it’ll turn out to be Idea<br />

Investment, where all that dreaming<br />

will pay off big time. (I absolutely want<br />

to acknowledge: Idea Investment is a<br />

crucial stage of some of your biggest,<br />

most ambitious projects. I’ll get back to<br />

that concept in a future post.)<br />

And the only way I will ever find<br />

out whether my project represents Idea<br />

Debt or Idea Investment is if I create a<br />

plan that breaks down the project into<br />

actionable steps, and then actually take<br />

those steps.<br />

You’ve grown up. You’ve changed.<br />

And all those old ideas you keep<br />

returning to and investing more in just<br />

because you feel like you ought to — I<br />

mean, they’re your ideas! They need<br />

care and feeding! When you kick them<br />

all out of the house, you’ll recover<br />

massive amounts of psychic energy.<br />

And that energy is what you will focus<br />

on the one thing you actually do want<br />

to be doing, right now. •<br />

Reprinted with permission of the original author. First appeared at jessicaabel.com.<br />

38 hacker bits


INTERESTING<br />

I built myself a 16×20-inch<br />

camera in 10 hours<br />

By GILES CLEMENT<br />

Syndicated from PetaPixel.com<br />

hacker bits<br />

39


While sitting in a coffee shop<br />

last Friday, I really didn’t<br />

want to answer any more<br />

emails so I went to a bar instead,<br />

ordered a pint and sketched out a bit of<br />

a doodle for a big camera. I then called<br />

my buddy Zach who shares my open<br />

schedule and vague ability with power<br />

tools, and he stopped by my studio an<br />

hour later.<br />

I explained what I wanted to do<br />

and showed him my napkin doodle. I<br />

think his reaction was something along<br />

the lines of “I have no idea what you’re<br />

talking about… but sure”. So we went<br />

to Home Depot and bought a bunch of<br />

wood and some screws.<br />

Ingredients<br />

My napkin drawing wasn’t exactly a<br />

plan and the camera kind of built itself<br />

by what materials we found walking<br />

around the aisles: 1/2×3” poplar for the<br />

back standard, 3/4×1” pine for the main<br />

rail and front standard, some in-floor<br />

heating tube and dowels for the bellows<br />

supports and really poor quality 1/4”<br />

plywood for the lens board. The most<br />

expensive thing was the bellows plastic,<br />

6 mil black, which I’d used before<br />

for making a darkroom in my old studio.<br />

They only sell it in 100’ rolls and<br />

that was $70.<br />

Total cost for materials was $168.<br />

Building the camera<br />

Back in the studio we turned on a<br />

playlist of James Bond theme music,<br />

cracked open several beers and began<br />

cutting stuff. The back standard came<br />

first since that would more or less decide<br />

the rest of the design. The standard<br />

was just a simple 16×20 frame with 1/4”<br />

stickers nailed around the inside to hold<br />

the ground glass and actual ambrotype.<br />

This was then fixed to a couple of 12”<br />

rails on the bottom which would fit<br />

snuggly to the bottom main rail with<br />

thumb screws to lock the focusing<br />

and a couple of lips on the bottom to<br />

prevent rocking.<br />

40 hacker bits


I’d roughly calculated how long<br />

the camera would have to be to make<br />

a portrait, around five feet total, so I<br />

made the bottom rail that length. It’s<br />

just a couple of 1×3/4” boards with four<br />

spacers glued and screwed evenly along<br />

the length.<br />

We needed a ground glass and<br />

while I’d read a bit about making them<br />

awhile ago, the process of using grinding<br />

compound sounded time consuming,<br />

so I just used an orbital sander and<br />

some 100 grit paper to grind the glass.<br />

At some point I’ll work on a better one<br />

since this isn’t super easy to view but it<br />

is functional.<br />

Next was the front standard — just<br />

a couple of pine sticks framed out with<br />

a 1/4” piece of plywood with a hole<br />

for the lens. So far so good. My main<br />

worry with building a camera of this<br />

size were the bellows, I’d seen people<br />

spend hundreds or thousands of dollars<br />

either making or ordering bellows and<br />

I wanted nothing to do with that. I’d<br />

also told my friends that I was going<br />

to build the camera in three hours, so I<br />

didn’t have the time.<br />

My solution was to put a telescoping<br />

support on all four corners between<br />

the front and rear standard. It’s just a<br />

piece of 1/2” plastic tube on one end<br />

and a 1/4” wood dowel on the other<br />

end. This allows the whole camera to<br />

slide back and forth for focusing while<br />

retaining the traditional shape of a large<br />

format camera.<br />

This brought us to the bellows. My<br />

friend Tristin had been helping out and<br />

cut four panels to size, then taped the<br />

bottom and side panels together. This<br />

was then fitted to the camera and we<br />

realized that we had two staple guns<br />

which didn’t work. Both guns were<br />

tinkered with, cursed at and hit several<br />

times, all to no avail. So we taped<br />

the bellows to the camera. Not ideal<br />

but functional. The top bellows panel<br />

was fitted and the lens was bolted to<br />

the front which pretty much made a<br />

camera.<br />

hacker bits<br />

41


Shooting the first photos<br />

It was 2am and we were pretty tired but<br />

I didn’t want to wait for the morning<br />

so we cleaned off a piece of glass<br />

and poured a plate. I should probably<br />

mention, if it hasn’t already become<br />

clear, that I wasn’t exactly prepared<br />

for this whole thing. I had managed<br />

to run by my local camera shop to get<br />

some 16×20 trays but they only had<br />

one and we’d need three: one for the<br />

silver nitrate, one for the rinse, and one<br />

for the fixer. So I scoured the studio<br />

and came up with a huge tupperware<br />

storage bin and one of my pelican cases<br />

to use instead.<br />

I had been a little nervous about<br />

pouring a plate this large. If you’ve<br />

ever tried the ball maze game, pouring<br />

a plate is a bit like that. You pour collodion<br />

on the plate and then move the<br />

plate around till the liquid flows evenly<br />

and completely across the surface without<br />

losing any over the edge and then<br />

pour the rest back into your collodion<br />

bottle.<br />

I definitely lost some collodion<br />

to the ground on this one and will<br />

definitely install a larger vent fan in my<br />

darkroom but it wasn’t nearly as bad as<br />

I’d thought. The glass plate was then<br />

submerged in the silver tray to sensitize<br />

and we went back in the studio to<br />

adjust the lights and get focus.<br />

Most large format cameras use<br />

a film holder which is light tight and<br />

allows the transport of the film to the<br />

camera. I hadn’t had time to build a<br />

holder so the plan was just to turn out<br />

all the lights and walk the sensitized<br />

plate to the camera, fire the strobes, and<br />

pray. Which we did.<br />

If you’ve ever sat in front of a<br />

studio strobe you know they’re bright.<br />

Now try turning out the lights for two<br />

minutes and then setting off one of the<br />

bigger commercially available strobes<br />

four feet from your face. Tristin’s<br />

exact words right after exposure were<br />

“F*****k that was bright.” Trooper.<br />

The rest of the process was the<br />

same as smaller plates, pouring an iron<br />

sulfate developer over the surface,<br />

waiting for an image to appear, rinsing<br />

and then fixing. I wasn’t really that<br />

optimistic that we’d get an exposure<br />

due to bellows factor and the generally<br />

haphazard approach to this camera but<br />

sure enough, a negative appeared and it<br />

looked great. A little overexposed due<br />

to the extended time it took to rinse of<br />

the developer on such a big plate but<br />

way better than I had expected.<br />

I’ve made a couple of plates since<br />

then and they’re getting better. They’re<br />

still not perfect but that’s why I’m in<br />

the wetplate game in the first place.<br />

Here’s the photo-making process,<br />

from start to finish: 16x20 Ambrotype.<br />

My next step is to make a proper<br />

film holder so we don’t have to subject<br />

people to such a massive change in<br />

light when taking photos and I’ll<br />

probably get a staple gun and attach<br />

the bellows properly. And if I can find<br />

a bigger lens, I’ll probably drink a few<br />

more beers and try to make a 20×24<br />

camera. Because I still hate answering<br />

emails. •<br />

Reprinted with permission of the original author and PetaPixel.com.<br />

42 hacker bits


OPINION<br />

Heisenberg<br />

developers<br />

You cannot observe a developer<br />

without altering their behavior<br />

By MIKE HADLOW<br />

First a story<br />

Several years ago I worked on a largish<br />

project as one of a team of developers.<br />

We were building an internal system to<br />

support an existing business process.<br />

Initially things went very well. The<br />

user requirements were reasonably<br />

well defined and we worked effectively<br />

iterating on the backlog. We were<br />

mostly left to our own devices. We had<br />

a non-technical business owner and a<br />

number of potential users who gave<br />

us broad objectives, and who tested<br />

features as they became available.<br />

When we felt that piece needed<br />

refactoring, we spent the time to do it.<br />

When a pain point appeared in the software<br />

we changed the design to remove<br />

it. We didn’t have to ask permission<br />

to do any of things, so long features<br />

hacker bits<br />

43


appeared at reasonable intervals, everyone<br />

was happy.<br />

Then came that requirement. The<br />

one where you try to replace an expert<br />

user’s years of experience and intuition<br />

with software. What started out as a<br />

vague and wooly requirement, soon<br />

became a monster as we started to dig<br />

into it. We tried to push back against<br />

it, or at least get it scheduled for a later<br />

version of the software to be delivered<br />

at some unspecified time in future. But<br />

no, the business was insistent, they<br />

wanted it in the next version.<br />

A very clever colleague thought<br />

the problem could be solved with a<br />

custom DSL that would allow the users<br />

“<br />

out of a problematic feature, the new<br />

guys would argue against it, saying it<br />

was ‘ivory tower’, and not delivering<br />

features. The PM would veto the work<br />

and side with the new guys.<br />

We became somewhat demotivated.<br />

After loosing an argument about<br />

how things should be done more than<br />

a few times, you start to have a pretty<br />

clear choice: knuckle down, don’t<br />

argue and get paid, or leave. Our best<br />

developer, the DSL guy, did leave, and<br />

the ones of us arguing for good design<br />

lost one of our main champions.<br />

I learnt to inflate my estimates,<br />

do what I was told to do, and to keep<br />

my imagination and creativity for my<br />

What started out as a vague and wooly<br />

requirement, soon became a monster<br />

as we started to dig into it.<br />

themselves to encode their business<br />

rules and he and another guy set to<br />

work building it. Several months later,<br />

he was still working on it. The business<br />

was frustrated by the lack of progress<br />

and the vaguely hoped for project<br />

delivery dates began to slip. It was all a<br />

bit of a mess.<br />

The boss looked at this and decided<br />

that we were loose cannons and the<br />

ship needed tightening up. He hired a<br />

project manager with an excellent CV<br />

and a reputation for getting wayward<br />

software projects under control.<br />

He introduced us to ‘Jira’, a word<br />

that strikes fear into the soul of a developer.<br />

Now, rather than taking a high<br />

level requirement and simply delivering<br />

it at some point in the future, we would<br />

break the feature into finely grained<br />

tasks, estimate each of the tasks, then<br />

break the tasks into finer grained tasks<br />

if the estimate was more than a day’s<br />

work.<br />

Every two weeks we would have a<br />

day long planning meeting where these<br />

tasks were defined. We then spent the<br />

next 8 days working on the tasks and<br />

updating Jira with how long each one<br />

took. Our project manager would be<br />

displeased when tasks took longer than<br />

the estimate and would immediately<br />

assign one of the other team members<br />

to work with the original developer to<br />

hurry it along.<br />

We soon learned to add plenty<br />

of contingency to our estimates. We<br />

were delivery focused. Any request to<br />

refactor the software was met with disapproval,<br />

and our time was too finely<br />

managed to allow us refactor ‘under the<br />

radar.’<br />

Then a strange thing started to<br />

happen. Everything slowed.<br />

Of course we had no way to prove<br />

it because there was no data from ‘pre-<br />

PM’ to compare to ‘post-PM’, but there<br />

was a noticeable downward notch in<br />

the speed at which features were delivered.<br />

With his calculations showing that<br />

the project’s delivery date was slipping,<br />

our PM did the obvious thing and<br />

started hiring more developers, I think<br />

they were mostly people he’d worked<br />

with before.<br />

We, the existing team had very<br />

little say in who was hired, and it did<br />

seem that there was something of a<br />

cultural gap between us and the new<br />

guys. Whenever there was any debate<br />

about refactoring the code, or backing<br />

evening and weekend projects. I found<br />

it odd that few of my new colleagues<br />

seemed to actually enjoy software<br />

development, the talk in our office was<br />

now more about cars than programming<br />

languages.<br />

They actually seemed to like the<br />

finely grained management. As one<br />

explained to me, “you take the next<br />

item off the list, do the work, check it<br />

in, and you don’t have to worry about<br />

it.” It relieved them of the responsibility<br />

to make difficult decisions, or take a<br />

strategic view.<br />

The project was not a happy one.<br />

Features took longer and longer to be<br />

delivered. There always seemed to be<br />

a mounting number of bugs, few of<br />

which seemed to get fixed, even as the<br />

team grew. The business spent more<br />

and more money for fewer and fewer<br />

benefits.<br />

44 hacker bits


Why did it all go so<br />

wrong?<br />

Finely grained management of software<br />

developers is compelling to a business.<br />

Any organization craves control. We<br />

want to know what we are getting in<br />

return for those expensive developer<br />

salaries. We want to be able to accurately<br />

estimate the time taken to deliver<br />

a system in order to do an effective<br />

cost-benefit analysis and to give the<br />

business an accurate forecast of<br />

delivery. There’s also the hope<br />

that by building an accurate<br />

database of estimates verses<br />

actual effort, we can fine tune<br />

our estimation, and by analysis<br />

find efficiencies in the software<br />

development process.<br />

The problem with this<br />

approach is that it fundamentally<br />

misunderstands the nature of software<br />

development. That it is a creative and<br />

experimental process. Software development<br />

is a complex system of multiple<br />

poorly understood feedback loops and<br />

interactions. It is an organic process of<br />

trial and error, false starts, experiments<br />

and monumental cock-ups. Numerous<br />

studies have shown that effective<br />

creative work is best done by motivated<br />

autonomous experts. As developers we<br />

need to be free to try things out, see<br />

how they evolve, back away from bad<br />

decisions, maybe try several different<br />

things before we find one that works.<br />

We don’t have hard numbers for why<br />

we want to try this or that, or why we<br />

want to stop in the middle of this task<br />

and throw away everything we’ve<br />

done. We can’t really justify all our decisions,<br />

many them are hunches, many<br />

of them are wrong.<br />

If you ask me how long a feature<br />

is going to take, my honest answer is<br />

that I really have no idea. I may have<br />

a ball-park idea, but there’s a long-tail<br />

of lower-probability possibilities, that<br />

mean that I could easily be out by a<br />

factor of 10. What about the feature<br />

itself? Is it really such a good idea?<br />

I’m not just the implementer of this<br />

software, I’m a stake holder too. What<br />

if there’s a better way to address this<br />

business requirement? What if we<br />

discover a better way half way through<br />

the estimated time? What if I suddenly<br />

stumble on a technology or a technique<br />

that could make a big difference to the<br />

business? What if it’s not on the road<br />

map?<br />

“<br />

Simple:<br />

give them autonomy.<br />

As soon as you ask a developer to<br />

tell you exactly what he’s going to do<br />

over the next 8 days (or worse weeks or<br />

months), you kill much of the creativity<br />

and serendipity. You may say that he is<br />

free to change the estimates or the tasks<br />

at any time, but he will still feel that<br />

he has to at least justify the changes.<br />

The more finely grained the tasks, the<br />

more you kill autonomy and creativity.<br />

No matter how much you say it doesn’t<br />

matter if he doesn’t meet his estimates,<br />

he’ll still feel bad about it. His response<br />

to being asked for estimates is twofold:<br />

first, he will learn to put in large<br />

contingencies, just in case one of those<br />

rabbit-holes crosses his path; second,<br />

he will look for the quick fix, the hack<br />

that just gets the job done. Damn technical<br />

debt, that’s for the next poor soul<br />

to deal with, I must meet my estimate.<br />

Good developers are used to doing<br />

necessary, but hard to justify work<br />

‘under the radar’, they effectively lie to<br />

management about what they are really<br />

doing, but finely grained management<br />

makes it hard to steal the time in which<br />

to do it.<br />

To be clear, I’m not speaking for<br />

everyone here. Not all developers<br />

dislike micromanagement. Some are<br />

more attracted to the paycheck than<br />

the art. For them, micromanagement<br />

can be very attractive. So long as you<br />

know how to work the system you can<br />

happily submit inflated estimates, just<br />

do what you’re told, and check in the<br />

feature. If users are unhappy and the<br />

system is buggy and late, you are not to<br />

blame, you just did what you were told.<br />

Finely grained<br />

management is a recipe<br />

for ‘talent evaporation’.<br />

The people who live and<br />

breathe software will leave<br />

– they usually have few<br />

problems getting jobs elsewhere.<br />

The people who<br />

don’t like to take decisions<br />

and need an excuse, will stay. You will<br />

find yourself with a compliant team<br />

that meekly carries out your instructions,<br />

doesn’t argue about the utility of<br />

features, fills in Jira correctly, meets<br />

their estimates, and produces very poor<br />

quality software.<br />

So how should one<br />

manage developers?<br />

Simple: give them autonomy. It seems<br />

like a panacea, but finely grained<br />

management is poisonous for software<br />

development. It’s far better to give high<br />

level goals and allow your developers<br />

to meet them as they see fit. Sometimes<br />

they will fail; you need to build in<br />

contingency for this. But don’t react to<br />

failure by putting in more process and<br />

control. Work on building a great team<br />

that you can trust and that can contribute<br />

to success rather than employing<br />

rooms full of passive code monkeys. •<br />

Reprinted with permission of the original author. First appeared at mikehadlow.blogspot.cl.<br />

hacker bits<br />

45


INTERESTING<br />

A badass way<br />

to connect<br />

programs<br />

together<br />

By JOE ARMSTRONG<br />

What is OSC?<br />

Open Sound Control is a binary<br />

protocol for exchanging data between<br />

machines.<br />

Open Sound Control is just<br />

about the worse possible name<br />

for a protocol since I’d thought<br />

for a long time that this protocol<br />

could only be used to control<br />

sounds. Nothing is further<br />

from the truth. OSC should be<br />

renamed OAC [Open Anything<br />

Control] which would be a far<br />

better name since it can be used<br />

to control anything.<br />

OSC-over-UDP is just OSC packed<br />

data sent over a UDP connection. My<br />

first serious encounter with OSC-over-<br />

46 hacker bits


UDP was when I attended strangloop<br />

and talked about The Mess We’re In.<br />

I bumped into Sam Aaron, the<br />

unstoppable force behind Sonic Pi.<br />

and said that it would be really cool to<br />

control Sonic Pi from Erlang…<br />

Sam told me that to control Sonic<br />

Pi all I had to do was send it OSC<br />

encoded messages over UDP.<br />

I was first rather skeptical to using<br />

OSC-over-UDP but have rapidly came<br />

to believe that this is a really-really<br />

good way to proceed. My initial dislike<br />

of OSC-over-UDP was colored by my<br />

JSON-over-TCP experience. TCP is<br />

session based which make life easy (for<br />

some of us) and JSON is popular. On<br />

the other hand UDP can suffer from<br />

packet loss and OSC is an obscure protocol<br />

- digging deeper I found myself<br />

being more and more attracted to OSCover-UDP.<br />

Why do I like<br />

OSC‐over‐UDP?<br />

To start with OSC is beautiful and what<br />

I call “simple by design” — more on<br />

this later. A complete OSC encoder is<br />

tiny and can be written in any decent<br />

language in a few pages of code. My<br />

(incomplete) implementation osc.erl<br />

is tiny. It’s trivial to implement and<br />

extremely efficient. JSON on the other<br />

hand is not so easy to implement.<br />

I’ve always been attracted to things<br />

that are simple and powerful. Simplicity<br />

means they can be implemented in<br />

few lines of code. Fewer lines of code<br />

mean less possibility of errors and less<br />

to maintain.<br />

Session based TCP programs are<br />

trivial to write in Erlang but a bugger in<br />

any sequential language. TCP uses the<br />

idea a session and the only rational way<br />

to program a session is as a process or<br />

(horrors) as a thread.<br />

In Erlang session management<br />

is easier than falling off a<br />

log — one session equals one<br />

controlling process and as many<br />

sub-processes as you feel like.<br />

In most other languages session<br />

management involves mutable state<br />

concurrency. A program that is a dozen<br />

lines of Erlang escalates into a mess of<br />

locks and mutexes or callbacks which<br />

in most languages is a thin layer over a<br />

pthreads implementation.<br />

For those of you who haven’t<br />

written a multi-threaded TCP socket<br />

server in C using pthreads I can only<br />

say “don’t go there, it’s not a pleasant<br />

experience.” I’ve been there done that,<br />

and have the grey hairs to prove it.<br />

UDP is a lot simpler than TCP<br />

and is far easier to use in sequential<br />

languages. There are no sessions in<br />

UDP only messages. Servers don’t have<br />

to be multi-threaded to support sessions<br />

but can be interrupt driven and run in a<br />

single thread. This is wonderful news<br />

for systems like Node.js whose concurrency<br />

model is non-existent and whose<br />

idea of having a fun time is throwing<br />

promises into the future and hoping that<br />

nobody breaks them.<br />

Well as anybody who has watched<br />

Casablanca knows, promises can be<br />

broken.<br />

For many years I’ve been saying<br />

that it would be nice to collaborate by<br />

sending message to each other and not<br />

by grocking around in each other’s<br />

messes. I basically don’t want to know<br />

how you’ve implemented your pile of<br />

shit, I just want to send it a message to<br />

tell it what to do. I’d naively assumed<br />

that something like Anything-over-TCP<br />

would be fine and easy to implement,<br />

so I made a system called UBF which<br />

is a layered on top of TCP and hoped<br />

that everybody would use it.<br />

I guess I’d underestimated the<br />

difficulty of implementing Anything-over-TCP<br />

in a sequential<br />

language. Just because it’s really<br />

really easy in Erlang doesn’t<br />

mean to say it’s easy in sequential<br />

languages.<br />

TCP sessions map 1:1 onto Erlang<br />

programs and the programs are trivial.<br />

But in a sequential language they map<br />

N:1 onto a single process, which is a<br />

pain in the butt.<br />

For easy of implementation nothing<br />

I know of beats OSC-over-UDP -<br />

it’s really easy.<br />

My first experience with this was<br />

at the Strangeloop conference in St<br />

Louis in 2014 — I bumped into Sam<br />

Aaron and we got talking. I asked him<br />

if I could remote control the Sonic Pi -<br />

and he said “sure just send it some OSC<br />

messages.” We sat down, I Googled a<br />

bit and found an OSC library for Erlang<br />

and ten minutes later we were collaborating.<br />

I could collaborate with him by<br />

sending him OSC messages over UDP<br />

and didn’t have to understand one iota<br />

of how his application was built and<br />

structured. It didn’t matter all I had<br />

to do was understand the messaging<br />

protocol.<br />

Time passed and I’d almost forgot<br />

about this, but the other day I started<br />

wondering how to make sounds. I’d<br />

done this in Fun with Swift, and Midi<br />

and wondered idly how the Sonic Pi<br />

did this.<br />

I thought to myself “I know what<br />

I’ll do, I’ll build the Sonic Pi from<br />

the sources and in doing so get to<br />

understand how the sound generating<br />

works.” Well as we all know building<br />

from the sources is not easy. I tried and<br />

failed and tweeted.<br />

I’m now at an impasse — I’m<br />

mailed some guys on the Sonic Pi list<br />

who have what we think to be an identical<br />

setup — only the build works for<br />

them and not for me. Does that sound<br />

familiar? You bet your sweet lives it<br />

hacker bits<br />

47


does. And why does it work for them<br />

and not for me? Answer: Because the<br />

initial state of our machines is different<br />

and we have know way of describing<br />

what the initial state is.<br />

A little more digging in the Sonic<br />

Pi code revealed that it was really the<br />

SuperCollider scsynth program that<br />

was making the noises and that this<br />

talked to the Sonic Pi by sending OSCover-UDP<br />

messages - I wonder where<br />

Sam Arron got this idea from.<br />

Time to learn the<br />

SuperCollider and trace<br />

the OSC messages<br />

Sam helped me trace the OSC messages<br />

to the SuperCollider and after a few<br />

hours hacking I could send messages to<br />

sysnth with OSC-over-UDP messaging.<br />

Now I can build my project<br />

without having to build nor understand<br />

that internal structure of the scsynth or<br />

even the Sonic Pi.<br />

Sam wants to add a few features to<br />

the Sonic Pi and we’ll try and do this<br />

with an OSC-over-UDP component<br />

written in Erlang. If this works it will<br />

show that we can collaborate without<br />

messing with each others code.<br />

All of this made me realize that the<br />

conventional way of collaboration is to<br />

mess with each others code, simply because<br />

it’s technically rather complicated<br />

to build session based servers using<br />

Anything-over-TCP semantics so the<br />

way we collaborate is an unintentional<br />

consequence of a bad (or nonexistent)<br />

concurrency model.<br />

Now I’m quite excited - the SuperCollider,<br />

Sonic Pi and Pure Data are<br />

all insanely great projects - if we can<br />

get them all talking together through<br />

communication channels when we can<br />

make a new way of interworking not<br />

based on the silly idea of performing<br />

open brain surgery on other peoples<br />

code.<br />

We can send messages to things<br />

and ask them to do things.<br />

Sending message to things to get<br />

them do do things is the central idea in<br />

OO programming, as Alan Kay wrote.<br />

Pity nobody does this properly for<br />

purely local applications.<br />

I’ve always thought that people<br />

should be allowed to program in their<br />

favorite programming language - if<br />

they like Badtran-7 they they should<br />

program in Badtran-7 but If want to<br />

collaborate with them I should not be<br />

forced to program in Badtran-7.<br />

I like to write my code in Erlang<br />

so to collaborate I’ll write my code<br />

in Erlang you write your code in<br />

Badtran-7 and we’ll communicate in<br />

Anything-over-Whatnot. For ease of<br />

implementation OSC-over-UDP looks<br />

really good.<br />

So what’s so good about<br />

OSC?<br />

To explain why I like OSC I’ll first<br />

back off and talk about Tag-Length-<br />

Value encodings.<br />

Tag-Length-Value (TLV) encodings<br />

are used to describe data structures in<br />

packets that can be send “on the wire”.<br />

TLV data structures are simple and<br />

look like this:<br />

+-----+--------+-------+<br />

| Tag | Length | Value |<br />

+-----+--------+-------+<br />

Tag says what the type of the data<br />

which follows is, Length is the size of<br />

the data and Value the data itself.<br />

One slight problem with TLV encodings<br />

is alignment. If we’re sending<br />

4 byte integers or 8 byte IEEE floats<br />

we’d want the items to be aligned on 4<br />

byte boundaries.<br />

For languages that don’t care about<br />

word alignment (like Erlang, Smalltalk,<br />

and a few others) byte aligned TLVs<br />

are efficient and extremely easy to<br />

implement.<br />

For word aligned languages, we<br />

want to align on word boundaries.<br />

The OSC protocol (Open Sound<br />

Control) protocol takes a different<br />

approach. It it’s Verb-Tag*-Value*<br />

encoded.<br />

First comes a Verb which is a zero<br />

terminated string padded to a four byte<br />

boundary. Then comments a sequence<br />

of tags (which is also encoded as a<br />

string) then a sequence of values - each<br />

value corresponds to a single tag.<br />

The tags are i for an integer d for a<br />

double s for a string and so on.<br />

So the tag string iisif means<br />

that the values in the packet are int32<br />

int32 string int32 float in that<br />

order. Both the encoder and decoder<br />

know how these data types are encoded<br />

so no additional information is necessary.<br />

The tag string also suffices as<br />

a type descriptor that accurately<br />

describes the type of the data in the<br />

message - yes OSC is strongly typed.<br />

48 hacker bits


Simplicity by design<br />

The interesting thing about OSC encoding<br />

is that:<br />

• It is extremely efficient.<br />

• Encoders/decoders can be implemented<br />

in a few lines of code.<br />

• It is strongly typed.<br />

• Complex nested data structures<br />

cannot be represented.<br />

The last point is interesting — it means<br />

that we’ll have to restrict our messages<br />

to flat data structure built from simple<br />

things like integers and strings.<br />

To my mind this is a good thing -<br />

this is simplicity by design. Most applications<br />

that I have seen do not require<br />

deeply nested complex data structures<br />

in the communication protocols - and<br />

if they use such data structures they’ve<br />

probably been designed by a committee<br />

(and yes 3GPP I’m looking at you :-).<br />

Let’s compare this to JSON -<br />

JSON is flexible, untyped, tricky<br />

to parse and represent and<br />

wasteful of space on the wire.<br />

In other words JSON has everything<br />

that a wire line protocol<br />

should not have.<br />

hacker bits<br />

49


Why binary protocols are<br />

important<br />

2014 was the tipping point, where<br />

more people access the Internet though<br />

mobile terminals (phones) than wireline<br />

terminals (fixed computers). For<br />

mobile data, every bit counts. The radio<br />

spectrum is a limited resource. Within<br />

a given mobile cell the total bandwidth<br />

available is a finite and fixed amount,<br />

and this must be divided by the number<br />

of device in the cell that are simultaneously<br />

communicating. This is why<br />

everything slows down in peak periods<br />

when everybody is connected up at the<br />

same time.<br />

It is therefore essential not to waste<br />

bandwidth — I think it is totally crazy<br />

to send JSON or XML “over the air”<br />

since this will degrade the performance<br />

of the applications giving a bad user<br />

experience and higher bills - since ultimately<br />

we pay for every bit of data.<br />

Even in fiber nets we pay one<br />

way or another - here the costs are in<br />

terms of energy - it uses more energy to<br />

encode/decode verbose data structures<br />

than well designed ones.<br />

In the Telcomms Industry there’s<br />

been a great deal of effort to minimize<br />

the overheads in communication protocols<br />

— ASN.1 sweats blood to save bits<br />

— which are then wasted by programmers<br />

sending JSON down the wire.<br />

Not only does JSON/XML on<br />

the wire waste energy, and costs more<br />

— the user experience in a congested<br />

net is degraded — applications that<br />

minimize net bandwidth will there be<br />

more attractive in a congested net than<br />

applications that waste bandwidth.<br />

When writing a distributed application<br />

where the components send messages<br />

to each other, you’d better know<br />

well in advance exactly what messages<br />

you’re going to send and receive and<br />

what their types are.<br />

OSC messages with type signatures<br />

seems to be the perfect<br />

balance between power and<br />

expressiveness.<br />

They are expressive — but not too<br />

expressive (limiting the types to flat<br />

sequences of atomic types) seems a<br />

good idea — it certainly gets the job<br />

done and are “good enough” for most<br />

purposes.<br />

If a protocol cannot be expressed<br />

in sequences of OSC messages it probably<br />

should not be used.<br />

Finding an appropriate level for<br />

encoding messages is difficult.<br />

At a low level of abstractions we<br />

could just send integers over the wire<br />

but this would be too low level. At a<br />

higher level we could use some form<br />

of S-expression (like XML or JSON,<br />

which are just verbose S-expressions)<br />

but this is too expressive.<br />

OSC seems to strike the right<br />

balance.<br />

OSC has an additional advantage<br />

— the internal representation of<br />

an OSC message in the programming<br />

language of your choice is easy - why<br />

is this? Precisely because OSC does<br />

not have deeply nested recursive data<br />

structures.<br />

If you parse XML or JSON you<br />

need to map the parse tree onto some<br />

object structure in your language, and<br />

since the parse trees in complex, the<br />

object in your programming language<br />

will be complex.<br />

The intrinsically flat structure of<br />

OSC is attractive, since not only the<br />

protocols are simple, but the code to<br />

handle then will have a simple flat<br />

structure — again simplicity by design<br />

rather than accident.<br />

We could also stick OSC messages<br />

in files, which would be easy to parse<br />

and again have the balance of expressiveness<br />

contra simplicity.<br />

One measure of how good a protocol<br />

is is the size of the implementation<br />

and the time it took to<br />

write it. As I said implementing<br />

OSC is really easy, thanks mainly<br />

to the simplicity of the design.<br />

I’ve written a number of XML<br />

parsers in my time, and it is not easy<br />

and there are some unpleasant edge<br />

cases. JSON parsers are also cumbersome<br />

beasts.<br />

To see just exactly how easy this is<br />

I’ve made a lttle GitHub project where<br />

to test these ideas. The (incomplete)<br />

OSC encoder is in osc.erl.<br />

The library is being used to connect<br />

to three diffent programs and is<br />

described in Controlling Sound With<br />

OSC Messages. •<br />

Reprinted with permission of the original author. First appeared at joearms.github.io.<br />

50 hacker bits


food bit *<br />

The waspy truth about figs…<br />

If you have ever eaten figs, then chances<br />

are you’ve eaten fig wasps as well. That’s<br />

because figs are pollinated by fig wasps<br />

that burrow deep into the fig fruit to lay their<br />

eggs and live off the sugary bounty. This form<br />

of you-scratch-my-back-and-I’ll-scratch-yours<br />

relationship is known as mutualism as it benefits<br />

both fig plant and fig wasp. But not all fig wasps<br />

will make it out of the fig – some die and their<br />

remains are absorbed by the fruit. And that in a<br />

nutshell, is how we end up eating fig wasps.<br />

* FOOD BIT is where we, enthusiasts of all edibles, sneak<br />

in a fun fact about food.


hacker bits<br />

HACKER BITS is the monthly magazine that gives you the hottest technology and startup stories straight from <strong>Hacker</strong><br />

News. We select from the top voted stories for you and publish them in an easy-to-read magazine format.<br />

Get HACKER BITS delivered to your inbox every month! For more, visit hackerbits.com.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!