Tag Archives: students

Lessons from a 2020 intern assignment

Post Syndicated from Kristian Freeman original https://blog.cloudflare.com/lessons-from-the-2020-intern-assignment/

Lessons from a 2020 intern assignment

This summer, Cloudflare announced that we were doubling the size of our Summer 2020 intern class. Like everyone else at Cloudflare, our interns would be working remotely, and due to COVID-19, many companies had significantly reduced their intern class size, or outright cancelled their programs entirely.

With our announcement came a huge influx of  students interested in coming to Cloudflare. For applicants seeking engineering internships, we opted to create an exercise based on our serverless product Cloudflare Workers. I’m not a huge fan of timed coding exercises, which is a pretty traditional way that companies gauge candidate skill, so when I was asked to help contribute an example project that would be used instead, I was excited to jump on the project. In addition, it was a rare chance to have literally thousands of eager pairs of eyes on Workers, and on our documentation, a project that I’ve been working on daily since I started at Cloudflare over a year ago.

In this blog post, I will explain the details of the full-stack take home exercise that we sent out to our 2020 internship applicants. We asked participants to spend no more than an afternoon working on it, and because it was a take home project, developers were able to look at documentation, copy-paste code, and generally solve it however they would like. I’ll show how to solve the project, as well as some common mistakes and some of the implementations that came from reviewing submissions. If you’re interested in checking out the exercise, or want to attempt it yourself, the code is open-source on GitHub. Note that applications for our internship program this year are closed, but it’s still a fun exercise, and if you’re interested in Cloudflare Workers, you should give it a shot!

What the project was: A/B Test Application

Workers as a serverless platform excels at many different use-cases. For example, using the Workers runtime APIs, developers can directly generate responses and return them to the client: this is usually called an originless application. You can also make requests to an existing origin and enhance or alter the request or response in some way, this is known as an edge application.

In this exercise, we opted to have our applicants build an A/B test application, where the Workers code should make a request to an API, and return the response of one of two URLs. Because the application doesn’t make request to an origin, but serves a response (potentially with some modifications) from an API, it can be thought of as an originless application – everything is served from Workers.

Client <-----> Workers application <-------> API
                                   |-------> Route A
                                   |-------> Route B

A/B testing is just one of many potential things you can do with Workers. By picking something seemingly “simple”, we can hone in on how each applicant used the Workers APIs – making requests, parsing and modifying responses – as well as deploying their app using our command-line tool wrangler. In addition, because Workers can do all these things directly on the edge, it meant that we could provide a self-contained exercise. It felt unfair to ask applicants to spin up their own servers, or host files in some service. As I learned during this process, Cloudflare Workers projects can be a great way to gauge experience in take home projects, without the usual deployment headaches!

To provide a foundation for the project, I created my own Workers application with three routes – first, an API route that returns an array with two URLs, and two HTML pages, each slightly different from the other (referred to as “variants”).

Lessons from a 2020 intern assignment
Lessons from a 2020 intern assignment

With the API in place, the exercise could be completed with the following steps:

  1. Make a fetch request to the API URL (provided in the instructions)
  2. Parse the response from the API and transform it into JSON
  3. Randomly pick one of the two URLs from the array variants inside of the JSON response
  4. Make a request to that URL, and return the response back from the Workers application to the client

The exercise was designed specifically to be a little past beginner JavaScript. If you know JavaScript and have worked on web applications, a lot of this stuff, such as making fetch requests, getting JSON responses, and randomly picking values in an array, should be things you’re familiar with, or have at least seen before. Again, remember that this exercise was a take-home test: applicants could look up code, read the Workers documentation, and find the solution to the problem in whatever way they could. However, because there was an external API, and the variant URLs weren’t explicitly mentioned in the prompt for the exercise, you still would need to correctly implement the fetch request and API response parsing in order to give a correct solution to the project.

Here’s one solution:

addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})


// URL returning a JSON response with variant URLs, in the format
//   { variants: [url1, url2] }
const apiUrl = `https://cfw-takehome.developers.workers.dev/api/variants`


const random = array => array[Math.floor(Math.random() * array.length)]


async function handleRequest(request) {
  const apiResp = await fetch(apiUrl)
  const { variants } = await apiResp.json()
  const url = random(variants)
  return fetch(url)
}

When an applicant completed the exercise, they needed to use wrangler to deploy their project to a registered Workers.dev subdomain. This falls under the free tier of Workers, so it was a great way to get people exploring wrangler, our documentation, and the deploy process. We saw a number of GitHub issues filed on our docs and in the wrangler repo from people attempting to install wrangler and deploy their code, so it was great feedback on a number of things across the Workers ecosystem!

Extra credit: using the Workers APIs

In addition to the main portion of the exercise, I added a few extra credit sections to the project. These were explicitly not required to submit the project (though the existence of the extra credit had an impact on submissions: see the next section of the blog post), but if you were able to quickly finish the initial part of the exercise, you could dive deeper into some more advanced topics (and advanced Workers runtime APIs) to build a more interesting submission.

Changing contents on the page

With the variant responses being returned to the client, the first extra credit portion asked developers to replace the content on the page using Workers APIs. This could be done in two ways: simple text replacement, or using the HTMLRewriter API built into the Workers runtime.

JavaScript has a string .replace function like most programming languages, and for simple substitutions, you could use it inside of the Worker to replace pieces of text inside of the response body:

// Rewrite using simple text replacement - this example modifies the CTA button
async function handleRequestWithTextReplacement(request) {
  const apiResponse = await fetch(apiUrl)
  const { variants } = await apiResponse.json()
  const url = random(variants)
  const response = await fetch(url)


  // Get the response as a text string
  const text = await response.text()


  // Replace the Cloudflare URL string and CTA text
  const replacedCtaText = text
    .replace('https://cloudflare.com', 'https://workers.cloudflare.com')
    .replace('Return to cloudflare.com', 'Return to Cloudflare Workers')
  return new Response(replacedCtaText, response)
}

If you’ve used string replacement at scale, on larger applications, you know that it can be fragile. The strings have to match exactly, and on a more technical level, reading response.text() into a variable means that Workers has to hold the entire response in memory. This problem is common when writing Workers applications, so in this exercise, we wanted to push people towards trying our runtime solution to this problem: the HTMLRewriter API.

The HTMLRewriter API provides a streaming selector-based interface for modifying a response as it passes through a Workers application. In addition, the API also allows developers to compose handlers to modify parts of the response using JavaScript classes or functions, so it can be a good way to test how people write JavaScript and their understanding of APIs. In the below example, we set up a new instance of the HTMLRewriter, and rewrite the title tag, as well as three pieces of content on the site: h1#title, p#description, and a#url:

// Rewrite text/URLs on screen with HTML Rewriter
async function handleRequestWithRewrite(request) {
  const apiResponse = await fetch(apiUrl)
  const { variants } = await apiResponse.json()
  const url = random(variants)
  const response = await fetch(url)


  // A collection of handlers for rewriting text and attributes
  // using the HTMLRewriter
  //
  // https://developers.cloudflare.com/workers/reference/apis/html-rewriter/#handlers
  const titleRewriter = {
    element: (element) => {
      element.setInnerContent('My Cool Application')
    },
  }
  const headerRewriter = {
    element: (element) => {
      element.setInnerContent('My Cool Application')
    },
  }
  const descriptionRewriter = {
    element: (element) => {
      element.setInnerContent(
        'This is the replaced description of my cool project, using HTMLRewriter',
      )
    },
  }
  const urlRewriter = {
    element: (element) => {
      element.setAttribute('href', 'https://workers.cloudflare.com')
      element.setInnerContent('Return to Cloudflare Workers')
    },
  }

  // Create a new HTMLRewriter and attach handlers for title, h1#title,
  // p#description, and a#url.
  const rewriter = new HTMLRewriter()
    .on('title', titleRewriter)
    .on('h1#title', headerRewriter)
    .on('p#description', descriptionRewriter)
    .on('a#url', urlRewriter)


  // Pass the variant response through the HTMLRewriter while sending it
  // back to the client.
  return rewriter.transform(response)
}

Persisting variants

A traditional A/B test application isn’t as simple as randomly sending users to different URLs: for it to work correctly, it should also persist a chosen URL per-user. This means that when User A is sent to variant A, they should continue to see Variant A in subsequent visits. In this portion of the extra credit, applicants were encouraged to use Workers’ close integration with the Request and Response classes to persist a cookie for the user, which can be parsed in subsequent requests to indicate a specific variant to be returned.

This exercise is dear to my heart, because surprisingly, I had no idea how to implement cookies before this year! I hadn’t worked with request/response behavior as closely as I do with the Workers API in my past programming experience, so it seemed like a good challenge to encourage developers to check out our documentation, and wrap their head around how a crucial part of the web works! Below is an example implementation for persisting a variant using cookies:

// Persist sessions with a cookie
async function handleRequestWithPersistence(request) {
  let url, resp
  const cookieHeader = request.headers.get('Cookie')

  // If a Variant field is already set on the cookie...
  if (cookieHeader && cookieHeader.includes('Variant')) {
    // Parse the URL from it using regexp
    url = cookieHeader.match(/Variant=(.*)/)[1]
    // and return it to the client
    return fetch(url)
  } else {
    const apiResponse = await fetch(apiUrl)
    const { variants } = await apiResponse.json()
    url = random(variants)
    response = await fetch(url)

    // If the cookie isn't set, create a new Response
    // passing in all the information from the original response,
    // along with a Set-cookie header, setting the value `Variant`
    // to the randomly selected variant URL.
    return new Response(response.body, {
      ...resp,
      headers: {
        'Set-cookie': `Variant=${url}`,
      },
    })
  }
}

Deploying to a domain

Workers makes a great platform for these take home-style projects because the existence of workers.dev and the ability to claim your workers.dev subdomain means you can deploy your Workers application without needing to own any domains. That being said, wrangler and Workers do have the ability to deploy to a domain, so for another piece of extra credit, applicants were encouraged to deploy their project to a domain that they owned! We were careful here to tell people not to buy a domain for this project: that’s a potential financial burden that we don’t want to put on anyone (especially interns), but for many web developers, they may already have test domains or even subdomains they could deploy their project to.

This extra credit section is particularly useful because it also gives developers a chance to dig into other Cloudflare features outside of Workers. Because deploying your Workers application to a domain requires that it be set up as a zone in the Cloudflare Dashboard, it’s a great opportunity for interns to familiarize themselves with our onboarding process as they go through the exercise.

You can see an example Workers application deploy to a domain, as indicated by the wrangler.toml configuration file used to deploy the project:

name = "my-fullstack-example"
type = "webpack"
account_id = "0a1f7e807cfb0a78bec5123ff1d3"
zone_id = "9f7e1af6b59f99f2fa4478a159a4"

Where people went wrong

By far the place where applicants struggled the most was in writing clean code. While we didn’t evaluate submissions against a style guide, most people would have benefitted strongly from running their code through a “code prettifier”: this could have been as simple as opening the file in VS Code or something similar, and using the “Format Document” option. Consistent indentation and similar “readability” problems made some submissions, even though they were technically correct, very hard to read!

In addition, there were many applicants who dove directly into the extra credit, without making sure that the base implementation was working correctly. Opening the API URL in-browser, copying one of the two variant URLs, and hard-coding it into the application isn’t a valid solution to the exercise, but with that implementation in place, going and implementing the HTMLRewriter/content-rewriting aspect of the exercise makes it a pretty clear case of rushing! As I reviewed submissions, I found that this happened a ton, and it was a bummer to mark people down for incorrect implementations when it was clear that they were eager enough to approach some of the more complex aspects of the exercise.

On the topic of incorrect implementations, the most common mistake was misunderstanding or incorrectly implementing the solution to the exercise. A common version of this was hard-coding URLs as I mentioned above, but I also saw people copying the entire JSON array, misunderstanding how to randomly pick between two values in the array, or not preparing for a circumstance in which a third value could be added to that array. In addition, the second most common mistake around implementation was excessive bandwidth usage: instead of looking at the JSON response and picking a URL before fetching it, many people opted to get both URLs, and then return one of the two responses to the user. In a small serverless application, this isn’t a huge deal, but in a larger application, excessive bandwidth usage or being wasteful with request time can be a huge problem!

Finding the solution and next steps

If you’re interested in checking out more about the fullstack example exercise we gave to our intern applicants this year, check out the source on GitHub: https://github.com/cloudflare-internship-2020/internship-application-fullstack.

If you tried the exercise and want to build more stuff with Cloudflare Workers, check out our docs! We have tons of tutorials and templates available to help you get up and running: https://workers.cloudflare.com/docs.

Cloudflare Doubling Size of 2020 Summer Intern Class

Post Syndicated from Matthew Prince original https://blog.cloudflare.com/cloudflare-doubling-size-of-2020-summer-intern-class/

Cloudflare Doubling Size of 2020 Summer Intern Class

Cloudflare Doubling Size of 2020 Summer Intern Class

We are living through extraordinary times. Around the world, the Coronavirus has caused disruptions to nearly everyone’s work and personal lives. It’s been especially hard to watch as friends and colleagues outside Cloudflare are losing jobs and businesses struggle through this crisis.

We have been extremely fortunate at Cloudflare. The super heroes of this crisis are clearly the medical professionals at the front lines saving people’s lives and the scientists searching for a cure. But the faithful sidekick that’s helping us get through this crisis — still connected to our friends, loved ones, and, for those of us fortunate enough to be able to continue work from home, our jobs — is the Internet. As we all need it more than ever, we’re proud of our role in helping ensure that the Internet continues to work securely and reliably for all our customers.

We plan to invest through this crisis. We are continuing to hire across all teams at Cloudflare and do not foresee any need for layoffs. I appreciate the flexibility of our team and new hires to adapt what was our well-oiled, in-person orientation process to something virtual we’re continuing to refine weekly as new people join us.

Summer Internships

One group that has been significantly impacted by this crisis are students who were expecting internships over the summer. Many are, unfortunately, getting notice that the experiences they were counting on have been cancelled. These internships are not only a significant part of these students’ education, but in many cases provide an income that helps them get through the school year.

Cloudflare is not cancelling any of our summer internships. We anticipate that many of our internships will need to be remote to comply with public health recommendations around travel and social distancing. We also understand that some students may prefer a remote internship even if we do begin to return to the office so they can take care of their families and avoid travel during this time. We stand by every internship offer we have extended and are committed to making each internship a terrific experience whether remote, in person, or some mix of both.

Doubling the Size of the 2020 Internship Class

But, seeing how many great students were losing their internships at other companies, we wanted to do more. Today we are announcing that we will double the size of Cloudflare’s summer 2020 internship class. Most of the internships we offer are in our product, security, research and engineering organizations, but we also have some positions in our marketing and legal teams. We are reopening the internship application process and are committed to making decisions quickly so students can plan their summers. You can find newly open internships posted at the link below.

https://boards.greenhouse.io/cloudflare/jobs/2156436?gh_jid=2156436

Internships are jobs, and we believe people should be paid for the jobs they do, so every internship at Cloudflare is paid. That doesn’t change with these new internship positions we’re creating: they will all be paid.

Highlighting Other Companies with Opportunities

Even when we double the size of our internship class we expect that we will receive far more qualified applicants than we will be able to accommodate. We hope that other companies that are in a fortunate position to be able to weather this crisis will consider expanding their internship classes as well. We plan to work with peer organizations and will highlight those that also have summer internship openings. If your company still has available internship positions, please let us know by emailing so we can point students your way: [email protected]

Opportunity During Crisis

Cloudflare was born out of a time of crisis. Michelle and I were in school when the global financial crisis hit in 2008. Michelle had spent that summer at an internship at Google. That was the one year Google decided to extend no full-time offers to summer interns. So, in the spring of 2009, we were both still trying to figure out what we were going to do after school.

It didn’t feel great at the time, but had we not been in the midst of that crisis I’m not sure we ever would have started Cloudflare. Michelle and I remember the stress of that time very clearly. The recognition of the importance of planning for rainy days has been part of what has made Cloudflare so resilient. And it’s why, when we realized we could play a small part in ensuring some students who had lost the internships they thought they had could still have a rewarding experience, we knew it was the right decision.

Together, we can get through this. And, when we do, we will all be stronger.

https://boards.greenhouse.io/cloudflare/jobs/2156436?gh_jid=2156436