A Computer Walks Into A Bar

AC

The Anatomy of the JMeter Load Test

Yesterday, my boss told me to write load tests for an endpoint in our Rails application. At first, I was all like:

But once I delved into the world of Apache JMeter, I realized that my knowledge of web requests would make understanding load testing a piece of cake.

Setup

In order to gain a better understanding of JMeter, I wanted to write load tests for the simplest type of Rails app – a Rails scaffold. Let’s set up our trusty Cat App:

1
2
3
4
rails new cat-app
cd cat-app
rails g scaffold cat name
rails s -p 8080

For the most part, this post assumes that you’ve been able to set up JMeter with your Rails app. In a nutshell, I added the location of the JMeter bin directory to my PATH, and then launched JMeter with the local host as -Jhostname:

1
2
export PATH=~/Development/apache-jmeter-2.13/bin:$PATH
JVM_ARGS="-Xms512m -Xmx2048m" && jmeter -Jhostname=127.0.0.1

Testing Components

To start testing the app, I added a Thread Group called Basic App Calls to the Test Plan (by right-clicking on Test Plan in the sidebar). Then, I added a Loop Controller called Cats to the Test Plan, and set the Loop Count to 10. All of the HTTP Requests that I tested were contained under the Cats Loop Controller.

I also added an HTTP Cookie Manager and a Summary Report to the Basic App Calls Thread Group.

The Simplest Case

Let’s start with our cats#index test. We shouldn’t need to pass any parameters into this request – all we have to do is visit /cats.

Rails set up this controller test:

1
2
3
4
5
test "should get index" do
  get :index
  assert_response :success
  assert_not_nil assigns(:cats)
end

So in order to test that this call works correctly, we just have to set up the correct HTTP Request Sampler under the Cats Loop Controller.

Under Server Name we’ll use our localhost, which gets entered as ${__P(hostname,)}. We’re running on port 8080, which we also need to specify.

Under HTTP Request, let’s set the method to GET and the path to /cats. The final settings look like this:

If we run our tests, we should see the request successfully hit the server and return a 200 status code. Easy!

Rails Authenticity Tokens

Now that we’ve created a simple load test, we’ll want to actually create a cat to test with. First off, we can set the settings, which are self-explanatory enough: Server Name ${__P(hostname,)}, Port Number 8080, HTTP Request POST, and Path /cats.

We know that we’ll need to post some data with our request – luckily, the HTTP Request section includes a list of parameters. Let’s add cat[name] as the Name, and a good name for a cat as the Value. I chose Meow.

However, if we run the tests, the summary report shows an 100% error percentage for Create Cat. If we look at the error in Terminal, we can see that the POST request returned a 422 Unprocessable Entity status code and a Can't verify CSRF token authenticity error. This makes sense – we know that we can’t post to a form in Rails without an authenticity token.

Luckily, with a little creativity, we can grab that token from another HTTP Request Sampler. Let’s set up an HTTP Request for cats#new: Server Name ${__P(hostname,)}, Port Number 8080, HTTP Request GET, and Path /cats/new.

When I opened up http://localhost:8080/cats/new, I could see that the form had an input tag: <input type="hidden" name="authenticity_token" value="TOKEN_HERE">. I wanted to grab that token and pass it into my POST params, which I could do with a Regular Expression Extractor nested under my new HTTP request. The Regex Extractor looks like this:

Whatever is within the parentheses gets captured and stored in a variable FORM_AUTH_TOKEN. So now, we’ll want to add another parameter to our POST request – Name: authenticity_token, Value: ${FORM_AUTH_TOKEN}. Make sure to check the Encoded checkbox for this parameter.

Now, if you run the tests, they should all return 0% errors.

Let’s See the Cat!

In order to make a call to cats#show we’ll need the specific ID of the cat that we wish to view. There are a few ways to grab this, but since I’m not familiar with JMeter, I decided to use a Regex Extractor like the one I used for the authenticity token. Since the create action redirects to the show page, the HTML response for create includes a link that has the cat’s ID. So I set up my Regex Extractor as follows:

Now that I saved the cat’s ID into a CAT_ID variable, I can embed it in the path for my cats#show request. The rest is pretty simple:

Destruction

Unfortunately, our testing took a turn for the evil – we had to destroy our cat! The call to cats#destroy is a DELETE request to /cats/${CAT_ID}. The only catch is that we need both our ID and our authenticity token, but they’re all set up, so it’s easy. Remember to encode the token:

Now, if we run our tests, we get no errors on any of the tests and we can start tracking performance!

Hooray!

Using Bootstrap Themes to Style Your Rails App

“Style is a way to say who you are without having to speak.” – Rachel Zoe

As a developer, I sometimes find myself wanting to integrate a preexisting themes into my web applications. But the Rails asset pipeline can make the setup of these themes tricky. So, when I utilize Bootstrap themes, I tend to follow a specific progression in order to get my fancy themes up and running.

Fancy Dog Gif

Let’s take a look at this process, using the Rival theme from the WrapBootstrap marketplace.

Requiring Dependencies

In order to use components from a theme, we’ll need to successfully require all of the themes assets in the vendor/assets/stylesheets and vendor/assets/javascripts folders. Let’s take a look at our theme in the browser:

Rival Theme

For this post, we’ll use an unstyled Cat App, and I’d love to grab this sortable gallery for my kittens. If we right-click on the theme page, we can view the page source.

View Page Source

CSS Dependencies

We’re going to want to grab the CSS and Javascript files from the theme and require them in the correct order in the Rails application. Let’s start with the CSS files – we’ll want to copy and paste the link tags into a new document in our text editor.

CSS Files

From there, let’s modify the link tags paths to fit the CSS Sprockets format, as demonstrated below. Not that the CSS Sprockets require does not include the .css extension.

Require CSS

Now, we’ll copy and paste the Sprockets into our application.css file.

CSS Sprockets

The last step is to ensure that all of the theme’s CSS files are included locally in the vendor/assets/stylesheets folder. In Rival, we’ll copy every file from Site/assets/css, as well as Site/assets/boostrap/css/bootstrap.min.css, into our vendor/assets/stylesheets folder. This will be different for each Bootstrap theme.

Javascript Dependencies

We’ll want to follow the same process for our Javascript script tags. Let’s copy them into a new document.

JS Files

One thing that I immediately notice is that one of the script tags links to an external resource, not a local file. I don’t know what to do with it yet, so we’ll deal with it later. Note that JS Sprockets do include the .js extension.

JS Sprockets

Like last time, we’ll copy and paste the Sprockets into our application.js file.

JS Sprockets 2

This time, we’ll copy every file from Site/assets/js, as well as Site/assets/boostrap/js/bootstrap.min.js, into our vendor/assets/javascripts folder. Now, if we look at the Javascript console, we get an error regarding the Google Maps API script that we skipped over before.

You’ve got to be kitten me!

JS Google Error

There’s no way to require external resources with Sprockets, so let’s add a javascript_include_tag to our application.html.erb file.

JS Include Tag

Now our kittens have no errors in the Javascript console! What a happy meow-ment!

Kittens Required

Integrating Components

Portfolio

Now that all of our dependencies have been required, we can start grabbing some claw-some components from the Bootstrap theme. If we Inspect Element for the portfolio, we can find the start of the portfolio code. We’ll copy the line <section class="module">, and our clipboard will contain all of the code between the start and end of the section element.

Grab Portfolio

Let’s paste that into a new document. Now, we have to decide which bits of that code we want to integrate into our Rails views, and, more speficially, what needs to be dynamic. We’ll want a portfolio item for each of our cat items, so let’s copy the list items code.

Portfolio Item

Now, let’s paste that into an ERB each loop:

ERB

We know that whenever we have li elements, we’ll want a ul element to wrap the list items, so we’ll grab that ul element, as well as the section and container div, from the theme code, and paste them before our ERB @cats.each loop.

ERB Header

And we’ll close the ul, div, and section tags after our ERB end – bonus points fur spotting the mis-indentation:

ERB Footer

If we refresh the page now, we’ll get a gallery full of broken images. How a-paw-ling! In order to see our adorable cats, we replace the img element with our ERB image_tag.

ERB Images

Refresh the page! Kittens!

Cat Gallery

BUT. Our kittens are still named “Corporate Identity”. That’s not a great name for one kitten, let alone many. So let’s replace “Corporate Identity” with the identifier Cat <%= cat.id %>.

ERB Names

Now, we can hover over our kittens in the gallery to get their IDs!

Cat 1

Filters

Now that the gallery is functioning properly, we can add filters. Let’s copy the <div class="row"> element, and paste it inside <div class="container">, before the each loop.

Filters

The theme’s filters now show up in the browser. Let’s modify them for our cats!

Demo Filters

The data-filter in each filter corresponds with the class name in our portfolio items. So, adding a filter with data-filter=".animated" means that clicking on it will keep all elements with the class animated.

Animated Filters

So, let’s use ERB to add a class name of animated to each cat list item where cat.animated is true.

Animated ERB

Now, if we click on the “Animated” filter, we’ll get some cat GIFs!

Animated Gallery

Purr-fect – hooray!

Happy Cat

Exploring State Diagrams

Part of the Flatiron School web development curriculum is a month-long Project Mode, so we as instructors advise the students on modeling their data. We always have the students map out their models and associations before beginning to code, but there are tools besides basic flowcharts that can help a project simplify its data. One of those tools is the state diagram.

What is a State Diagram?

Wikipedia gives an overview of state diagrams:

State diagrams are used to give an abstract description of the behavior of a system. This behavior is analyzed and represented in series of events, that could occur in one or more possible states.

Some more research leads to the fact that state diagrams are representations of state machines. Vaidehi Joshi wrote two excellent blog posts that explain what state machines are, as well as how to implement them in Ruby. In short:

At the risk of sounding a bit philosophical, it all boils down to actions that are taken, and the reasons we take certain actions. State machines are how we keep track of different events, and control the flow between those events.

First State Steps

In order to get a bit more practice modeling data, I’m going to create a state diagram to represent a Movie object. From Mitch Boyer, I received this list of production states:

  • Development: concept, develop screenplay, build core team, funding
  • Pre-Production: refine script, build crew, casting, location scouting, contracts, etc.
  • Production: shooting the movie
  • Post-Production: edit, music/sound mix, VFX, color correct
  • Distribution: festival circuit, VOD services (video on demand), etc.

That’s a lot of information! Time to break it down. I’ll start with a simple action – putting each of the five production states into nodes:

Where Can We Go From Here?

Rather than try to list all possible transitions between production states in a Movie, I’ll attack one node at a time. From the first node (Development), I can move forward one state (Pre-Production). From the second node (Pre-Production), I can move forward one state (Production) or backward one state (Development). I can start to see a pattern – at any point, I can move onto the next state or return to the state that came before. At any point, I can start over and return to the drawing board (Development).

Represented with flowchart arrows, my diagram now looks like this:

…And How Do We Get There?

The next step is to figure out what actions need to be taken to move from one state onto the next one. For me, it helps to think of each state as having an entry gate – what conditions need to be fulfilled for admission to a state?

Let’s take the first two nodes – Development and Pre-Production. According to our list, the development stage consists of developing a concept, developing screenplay, building core team, and funding the project. It’s impossible to move on without funding and a developed idea; those are the requirements. So if I call an action develop_and_fund, my Movie should be ready for the Pre-Production state.

I can figure out my entry gates for each step forward:

Naming the backwards steps is a little trickier. For example, at what point is a project no longer in Post-Production, but rather in Production again? When we need more footage. The final state diagram looks like this:

Why Use State Diagrams?

  1. Simplicity. State diagrams allow us to represent the way that objects evolve as certain actions occur. Since information is represented visually, we can more easily point out its flaws – for example, we might decide that a Movie cannot move from Production back to Pre-Production, because the Production state will deplete some of the movie’s funding. We may need to rerun develop_and_fund before we can return to the Pre-Production state.

  2. Communication. State diagrams can help us communicate the way systems will be laid out to non-technical team members.

  3. Organization. Since state machines can only exist in one state at a time, we can easily sort our Movies by progress. Furthermore, we know that API calls to each different state will return mutually exclusive sets of objects.

Hope you’ve enjoyed this simple example!

Understanding Procs for Sorting in Ruby – Part Two

Recap

Last time, we discussed procs and how to use them to set default blocks for Ruby methods.

A reminder:

1
2
3
4
5
6
7
8
9
10
11
def do_something(word, &block)
  normalized_block = block || Proc.new{ |word| word.capitalize }
  normalized_block.call(word)
end

do_something("hello")
  => "Hello"
do_something("hello"){ |word| word.capitalize }
  => "Hello"
do_something("hello"){ |word| word.upcase }
  => "HELLO"


Insertion Sort – Integers

According to Wikipedia, insertion sort “is a simple sorting algorithm that builds the final sorted array (or list) one item at a time.” Essentially, insertion sort works by keeping track of a sorted sub-list, and placing each element in the correct position in that sorted sub-list.

First, let’s implement insertion sort with simple integers in ascending order.

So if we implement a method that inserts an element at the correct place in a sorted array, this sort should be easy. If the element is less than or equal to any other element in the sorted array, we should insert the new element before this existing element; otherwise, we should put the new element at the end:

1
2
3
4
5
6
def insert_in_right_place(sorted_list, element)
  sorted_list.each_with_index do |list_el, i|
    return sorted_list.insert(i, element) if element <= list_el
  end
  sorted_list << element
end

Again, to sort an array of integers, we just have to iterate through it, placing each element in the sorted sub-list:

1
2
3
4
5
6
7
def sort(array)
  sorted = []
  array.each do |element|
    sorted = insert_in_right_place(sorted, element)
  end
  sorted
end

This can be refactored as:

1
2
3
def sort(array)
  array.inject([]) { |sorted, element| insert_in_right_place(sorted, element) }
end

Sort By Condition

But what if we want to sort by an optional, user-entered block? ENTER: PROCS.

In Ruby, the spaceship operator a <=> b compares two items, returning 1 if a > b, 0 if a == b, and -1 if a < b. For example, 3 <=> 2 returns 1, whereas 2 <=> 3 returns -1. 2 <=> 2 returns 0.

Let’s give our sort an optional block variable &block, so the user can enter his or her own sorting condition. The default condition should be the typical a <=> b comparison. Now, #sort becomes:

1
2
3
4
def sort(array, &block)
  normalized_block = block || Proc.new{|a, b| a <=> b}
  array.inject([]) { |sorted, element| insert_in_right_place(sorted, element, normalized_block) }
end

This block becomes what we check in #insert_in_right_place, which becomes:

1
2
3
4
5
6
def insert_in_right_place(sorted_list, element, block)
  sorted_list.each_with_index do |list_el, i|
    return sorted_list.insert(i, element) if block.call(element, list_el) < 1
  end
  sorted_list << element
end

So let’s try some examples:

1
2
3
4
["aardvark", "deer", "elephant", "blowfish", "hamster", "crocodile", "cat"].sort
  => ["aardvark", "blowfish", "cat", "crocodile", "deer", "elephant", "hamster"]
["deer", "blowfish", "hamster", "crocodile", "cat"].sort{ |a, b| a[1] <=> b[1] }
  => ["cat", "hamster", "deer", "blowfish", "crocodile"]


Understanding Procs for Sorting in Ruby – Part One

What is a Proc, Anyway?

According to the Ruby documentation, “Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables.” But what does that really mean?

Let’s do some experimentation with Procs.

1
2
3
4
5
proc = Proc.new{ |phrase| phrase.upcase }
  => #<Proc:0x007f99a20904c8@(irb):1> 

proc.call("hello!")
  => "HELLO!"

So it looks like a proc is a set of instructions inside of a variable. If I run the #call method on the proc, the arguments that I pass into #call will be passed into the block. Since I entered proc.call("hello!"), Ruby returned "hello!".upcase. Likewise, proc.call("how's it going?") returns "HOW'S IT GOING?".

Let’s try a longer one:

1
2
3
4
5
6
7
8
capital_split = Proc.new do |phrase|
  phrase.upcase!
  phrase.split("")
end
  => #<Proc:0x007fb182859ce8@(irb):1>

capital_split.call("bingo")
  => ["B", "I", "N", "G", "O"]

Again, whatever we pass into #call gets passed into our block. This is starting to make sense!

Normalizing Ruby Blocks

One important use of procs is their ability to set a default block for a Ruby method. Consider the method #do_something that takes a word and passes it into a block:

1
2
3
4
5
6
def do_something(word)
  yield(word)
end

do_something("hello"){ |word| word.capitalize }
  => "Hello"

But what if we want #do_something to capitalize its argument if if we don’t call it with a block. As it stands, we’ll get an error if we try to call #do_something without a block:

1
2
do_something("hello")
LocalJumpError: no block given (yield)

If we pass in another argument that starts with &, our block gets captured in that variable, as a proc. So we can rewrite our #do_something method as:

1
2
3
4
5
6
7
8
9
def do_something(word, &block)
  block.call(word)
end

do_something("hello"){ |word| word.capitalize }
  => "Hello"

do_something("hello")
NoMethodError: undefined method `call' for nil:NilClass

Now, setting a default block is a breeze:

1
2
3
4
5
6
7
8
9
10
11
def do_something(word, &block)
  normalized_block = block || Proc.new{ |word| word.capitalize }
  normalized_block.call(word)
end

do_something("hello")
  => "Hello"
do_something("hello"){ |word| word.capitalize }
  => "Hello"
do_something("hello"){ |word| word.upcase }
  => "HELLO"

POWERFUL! Next time, we’ll use our newfound proc powers to build a sort.

Balancing Beauty and the Technological World

Last week, I went stargazing.

I live in New York City, so I couldn’t see many stars, unfortunately. But as my eyes became accustomed to the shades of the night, a few dim specks of light emerged from the seemingly endless fog. As I breathed in the crisp late April evening, I felt present. I was there.

In today’s society of constant connection, I find that I often forget to take time out of my day to appreciate my surroundings. I’ve passed away numerous hours clicking through an endless loop of social media websites – Facebook, to Twitter, to Pinterest, to YouTube, back to Facebook. Subway rides are filled with podcasts, music, audiobooks. I rarely have to experience boredom, but I’ve also let precious moments slip by without notice.

In spite of my reflections on presentness, I really enjoy my career as a web developer. Coding is a creative activity that allows us to build tools greater than ourselves – and I’ve been interested in computers and technology for as long as I can remember. Even my elementary school assignments were typed in Microsoft Creative Writer. So how can I balance my love of programming with a feeling that the way that we consume technology is just not right?

The Problem with Instant Access

When I was in college, I dated a guy whose Blackberry was almost an extension of his arm. We would frequently eat meals together, as couples do, and he would often get distracted upon receiving an email. “Hold on,” he would say, “This email is time-sensitive.” In retrospect, I’ve realized that it was in fact the conversations that were truly time-sensitive. I’m 100% sure that all of the emails were still there once our face-to-face conversations were over.

The topic of our networked society and its effects is common among modern research – such as social psychologist Sherry Turkle’s book Alone Together (2011). According to Turkle, interactions like the aforementioned are prevalent. Turkle, who works at MIT, says in an interview, “The idea that we should put each other on pause as though we were machines in order to attend to those who are not present has become commonplace. It needs to be examined. I don’t think that is how we want to treat each other.”

Furthermore, the ease at which we can interact on a surface level often reduces the urgency with which we seek out deeper interactions. Turkle states, “We Facebook-friend people who do not know their commitment to us and similarly, we are unsure of what commitment we have to them. They can, in fact, be more like ‘fans’ than friends. But their presence can sustain us and distract us and make it less likely for us to look beyond them to other social encounters. They can provide the illusion of companionship without the demands of friendship, without the demands of intimacy.”

Many agree with the idea that social networks actually distance us from meaningful relationships. In fact, if you visit Google and type in “social media creates,” the first autocomplete hit is “social media creates isolation.”

Appearing Alright

A relatively recent story that really stuck with me is that of the tragic suicide of Madison Holleran, a 19-year-old track runner at UPenn. Madison took her life in January 2014, by jumping off of a nine-story parking garage. A recent article published in ESPN magazine illustrates that Madison’s social media pages “concealed her reality.” The article reads:

THE LIFE MADISON projected on her own Instagram feed was filled with shots that seemed to confirm everyone’s expectations: Of course she was loving her first year of college. Of course she enjoyed running. Her mom remembers looking at a photo on her feed and saying, “Madison, you look like you’re so happy at this party.”

“Mom,” Madison said. “It’s just a picture.”

As we maintain our Facebook and Instagram accounts, we generally only share the positive aspects of our lives, the parts we want to broadcast. This creates a problem when we start to contrast our lives – and all of the problems within them – and the seemingly-perfect “lives” that our friends display. We begin to feel alone in our mixed emotions; we forget that sadness, like joy, is universal.


My latest Instagram photo – my filtered life

The ESPN article compares this phenomenon to Instagram itself:

With Instagram, one thing has changed: the amount we consume of one another’s edited lives. Young women growing up on Instagram are spending a significant chunk of each day absorbing others’ filtered images while they walk through their own realities, unfiltered. In a recent survey conducted by the Girl Scouts, nearly 74 percent of girls agreed that other girls tried to make themselves look “cooler than they are” on social networking sites.

I’m not preaching against Instagram – I have fun documenting as much as the next person. But I think we should work a little harder to spread awareness that Instagram real is not real real. And we should remember that anything in excess is dangerous; social media is no exception.

Being Responsible Consumers

Like I said before, I love technology.

And I love my job, as a web development instructor at The Flatiron School. The opportunity to teach driven adults to empower themselves is so rewarding – the best way to renew someone’s excitement about life is to give them a superpower, and I feel like coding is that. It’s problem-solving, innovating. It’s fun.

Another company that we frequently work with is DoSomething.org. DoSomething.org describes itself as “one of the largest global orgs for young people and social change, our 3.6 million members tackle campaigns that impact every cause, from poverty to violence to the environment to literally everything else.” In my opinion, the organization uses the power of technology and social media in the perfect way – to extend its reach and inspire people to impact positive social change.

While discussing this topic with a friend the other day, he pointed out an interesting phenomenon. On the F train in Brooklyn, there’s a point at which the train comes above ground. If you look out the window, you can see the Statue of Liberty. And the kids do – while the adults always pull out their phones.

Just like anything, consuming technology (even for us engineers) is all about balance. So I’m issuing myself a challenge: to notice one new thing each day. Feel free to join me :) We can strive for a future full of innovation – but let’s try not to forget beauty.

What I’ve Learned About Life Through Teaching Adults to Code

Dance Lesson at Flatiron!

Yesterday marks the end of my eighth week as a web development instructor at the Flatiron School. I feel immensely lucky for the chance to work with such a driven group of coworkers and students “to align education with reality.” In honor of this two-month-iversary, here are a few things I’ve learned:

Being a Beginner Takes Courage

Six months ago, I enrolled at Flatiron after a year of freelancing as a theater lighting designer. As a 23-year-old New Yorker, many of my friends are still in the “transition” period; they’re either looking to become more established in their chosen fields or working subpar jobs to gain experience and open more exciting doors. Even given my relatively short stint working in theater and my young group of friends, the career shift felt like a huge one.

In contrast, many of my students left long, successful careers to learn to code full-time. I can’t imagine what that must feel like, but having seen the positive change in some of my classmates who did the same, I know that the payoff can be enormous. For me, every day is a reminder that the best things in life come from hard work and struggle.

A Positive (Or Negative) Attitude Is Contagious

Last week, Seiji, one of my students, organized “Club Euler,” essentially a student study group that meets half an hour before school to work through complex puzzles. Half an hour before school means extending an already rigorous day of 9-6 coding to begin at 8:30 in the morning. In spite of the early morning and the time commitment, most of the class chose to attend Club Euler twice last week.

I think the high interest reflects both the inherent intellectual curiosity of our students and the sense of community that Flatiron fosters. Being a student and then a coworker at Flatiron reminded me that the success of a team feels much greater than personal achievements do.

There Is Always More To Learn

In life, most careers/hobbies/activities have some limiting factor. Team sports and theater are limited by other people – you can’t play soccer or direct Hamlet without a team on board. Art and cooking are limited by supplies; once you run out of paint, you’re done painting. In a way, I feel like coding is less restrictive than many other things. Once you make the initial investment and get a computer, you have access to the limitless ability to learn and to code (sure, you need electricity for battery, but that’s easy).

When I was working in theater, a more experienced designer, Reid Thompson, gave me excellent advice: be a sponge. Working in web development makes this so easy, as code is constantly evolving. I try to learn something new every day!

The Bottom Line

All in all, I am thrilled that my first full-time job constantly demonstrates how important it is to strive for happiness–your own and that of the people around you. Can’t wait to see what new lessons the next two months have in store!

Hackers and Theater-Makers

This post was originally published on the Flatiron School Blog.

When I decided to enroll at the Flatiron School and shift my career from theater lighting design to web development, I worried unnecessarily that I would lose my drive to create. In practice, I constantly meet other developers with creative passions. My mentor, who I met through the Fog Creek Fellowship, is also a musician who keeps guitars in his office. One of my current Flatiron School students used to be a curator. The list goes on.

The fact that I’ve met a surprisingly large number of creative people in the NYC tech community may be explained by an essay written by programmer and writer Paul Graham entitled “Hackers and Painters,” which was one of the first readings assigned to me as a Flatiron School student. In his essay, Graham enumerates the similarities between computer programming and art. He explains:

What hackers and painters have in common is that they’re both makers. Along with composers, architects, and writers, what hackers and painters are trying to do is make good things.

Graham makes a number of excellent points in his essay; hackers and painters do indeed share many traits. However, I see a few key differences between web developers and painters that imply web development may in fact be more akin to theater-making than to painting.

Development Is Collaborative

Although programming is often thought of as a solitary activity, I haven’t found that stereotype to be true. Working with my peers on final projects was one of the most valuable experiences from my time as a Flatiron School student. Each member of the group brought a unique perspective, as well as a different set of strengths.

The benefits of working with others to complete a task are articulated in dancer and choreographer Twyla Tharp’s book The Collaborative Habit. In the book, Tharp explains how collaboration inherently grants new insight:

As a practical reality, let’s look at collaboration with a single partner. We bounce ideas off another person. Then the other person volleys them back to us. That exchange makes us hear our ideas with new ears for the simplest of reasons—what our partners say is not a literal repetition of what we said.

Theater at its core is a collaborative art form. Most successful production staffs include a director, a set designer, a lighting designer, a costume designer, and a sound designer, all working closely to realize the same vision. I’ve learned that a team full of talented specialists creates a spark. As Tharp states, “People in a good collaboration accomplish more than the group’s most talented members could achieve on their own.”

The open-source movement relies on this philosophy that multiple people working on different aspects of a project creates something greater than the sum of the individual parts. As I’m writing this blog post, Rails has 2,596 contributors on GitHub. Many tech companies have their developers program in pairs, in order to optimize efficiency, learning, and satisfaction and minimize code defects. And just recently, one of my Flatiron students declared, “It’s so rewarding to see how others at my table approach a problem. They think about it in completely different ways than I do.”

Application Evolve With Their Users

Unlike most paintings, works of theater continue to evolve even after they are revealed to an audience. What results is a living, breathing work of art that responds to human interaction. In his monumental book The Empty Space, theater and film director Peter Brook outlines an experiment in audience influence, involving an amateur actor reading a speech from Henry V:

The amateur actor was to read the speech again, stopping for a moment after each name: the audience was to endeavour silently in the pause to recall and put together its impressions of Auschwitz and Agincourt, to try to find a way of believing that these names were once individuals, as vividly as if the butchery had occurred in living memory…Now the audience’s concentration began to guide [the actor]: his inflexions were simple, his rhythms true: this in turn increased the audience’s interest and so the two-way current began to flow. When this was ended, no explanations were needed, the audience had seen itself in action, it had seen how many layers silence can contain.

Professional theater productions hold open “previews” before the official opening night. These previews allow the team to continue shaping the show based on audience response.

Similarly, most web applications continue to grow even after they are deployed. Here at the Flatiron School, students present their projects to their classmates and instructors throughout the building process, in order to get feedback from potential users.

But Why Does This Matter?

What I think developers, painters, and theater-makers all have in common is the desire to understand and contribute to the human experience. In order to do that, we must absorb our surroundings and let every interaction influence our work. In “Hackers and Painters,” Graham writes:

Empathy is probably the single most important difference between a good hacker and a great one. Some hackers are quite smart, but when it comes to empathy are practically solipsists. It’s hard for such people to design great software, because they can’t see things from the user’s point of view.

Developers can learn about empathy through great works of theater, and theater-makers can uncover truths about humanity through the ways in which people interact with applications. Regardless of our medium or our motivations—to make life more convenient, more beautiful, more entertaining—artists and programmers alike create for a better world.