Monday, November 10, 2014

A machine-readable resume

Anyone who's known me (professionally) for long knows that I've been a fan of microformats. Note 1 One of my early projects at PayPal was to write component code that used the hCard microformat Note 2 to mark up addresses. This little Easter egg Note 3would allow merchants with repeat customers to add contact information to their systems easily using any the vcard reader plug-ins.

You might be asking why I'm such a fan of microformats - and that's an easy question to answer. Our goal – as designers and developers – must be to make information more readable, Note 4 and more searchable, than it ever has been. A large part of the reason I'm a fan of microformats is the same reason I'm a huge fan of semantic HTML – it's more readable and understandable, not only by people, but by machines as well.

The next question may be "why is that important for resumes". Machines generally lack bias, and bias is a huge issue, especially in evaluation of resumes – you can read more about such bias on my post "What's in a name?" – which is why when friends went to work at LinkedIn, I put the words in their ear that they should use the hResume microformat. Note 5

A few short years ago, the hResume (and its related hCard format) were the only significant efforts in to create an HTML resume that would be a candidate for the Semantic Web. Time moves quickly on the Internet, however, and I should note that the hCard and hResume formats have been 'deprecated' in favor of the new formats – h-card and h-resume – and since Google, Bing, and Yahoo! joined together to create microdata schemas Note 6 you've (almost) had another way to mark up a resume. Granted, the microdata way takes more work because there isn't a format specifically for resumes, you have to cobble it together, but it's fairly easily done, and I'm going to tell you how while also describing how to mark up the data in both hResume and h-resume formats. This approach will give you a resume that's readable by nearly every bot crawling the web.

Getting Started

Note: before you go any further, it is important that you consider how much personal information you post on the web. You certainly need a name and some way for people to contact you, but more than that could put you at risk, and only you can evaluate the degree of risk. You ought also make a plan for re-evaluating that risk periodically.
First, let's think about a resume for a moment. Every resume is basically a combination of personal data and event data. You could think of it in other ways, but that doesn't really make sense. Every job you've ever had is an event organized by your employer, and every educational session you've attended is an event organized by the institution you attended. Once we've figured this out, it's relatively easy to put together a resume.

Now let's start with your code…we'll start with the contact information, which is typically where a resume begins. In order to be as complete as possible, I'm going to use all three formats – the two microformats: hResume and h-resume, and the microdata format, which we'll basically be creating. One small note here - there will be sections that I have marked up using tags that you may wish to replace with other tags; for example, a job description could easily be an ordered or unordered list rather than a paragraph, so feel free to use the tag that best describes the data you're presenting.

If you're using the h-resume format, you'll need to wrap all your information in a container with the class h-resume (same if you're using the hResume format), so feel free to use either a DIV tag or a SECTION tag as long as you use hResume and h-resume in the class attribute.

<section class="hResume h-resume">
  [your resume here]
</section>

You will not need this markup if your intention is to only use microdata, because there is no microdata schema for a resume or CV - this only applies to the hResume and h-resume formats. If schemas.org decides to create a resume schema, you could easily add the itemscope and itemtype attributes to this section.

Contact Information

The first section we're going to add to the resume is the contact information. It's typically the first section on any resume, so it's as good a place to start as any. For the microformats the sections will need to be identified and it's a good practice to identify the sections with some sort of header, so we're going to use the pattern where we have a header followed by identified content blocks. Since contact information is fairly simple as a h-card or Person object, I'll just go straight to the code where you'll notice I'm using a mixture of class attributes used by h-card (including contact, p-contact vcard and h-card) Note 7 and itemprop attributes (including name, addressLocality, and addressCountry). Note 8

One other note - I'm using a class name called "clipped" that hides content by using an absolute position and the CSS "clip" property (e.g. .clipped { clip:rect(0 0 0 0); clip:rect(0, 0, 0, 0); position:absolute; }). This approach makes content accessible in a way that setting the "display" property to "none" does not.

<section class="hResume h-resume">
  <section>
    <header>Contact</header>
    <div class="contact p-contact vcard h-card" itemscope="" itemtype="http://schema.org/Person">
    <p class="fn p-name" id="contact-p-name" itemprop="name">[your name]</p>
    <p class="adr p-adr" itemprop="address" itemscope="" itemtype="http://schema.org/PostalAddress">
      <span class="locality p-locality" itemprop="addressLocality">[locality]</span>
      <abbr class="region p-region" itemprop="addressRegion">[region]</abbr>
      <span class="postal-code p-postal-code" itemprop="postalCode">[postal code]</span>
      <abbr class="country-name p-country-name" itemprop="addressCountry">[country code]</abbr>
    </p>
    <p class="email">
      <span class="type clipped">[email type, e.g, "Work" or "Personal"]</span>
      <a class="value u-email" href="mailto:[email address]" itemprop="email">[email]</a>
    </p>
    </div>
  </section>
</section>

If you're wondering why I've included the country name, keep in mind that bots have a difficult time determining context. They could use a language code to guess about where you are, if you have it...but what about people who publish their resumes in a language or for a place other than where they're currently located - they'll want some way to identify where they're located that is not associated with the document language code. Also, note that I've added an ID attribute to the "name" element (identified by the "fn" or "p-name" class and the "name" itemprop) – that will be used later in the code as part of the h-resume format.

Summary or Objective

The next section you may want to include is the "summary" or objective. Why might you want to include a summary? It's basically the tl;dr section for your post. If you're using the hResume or h-resume format, use the class names "summary" and "p-summary", respectively. Something like the following should suffice.

<section>
  <header>Summary</header>
  <p class="summary p-summary">[your summary here]</p>
</section>

Note that this section is not available in the microdata version. An alternative to leaving it out completely is to add it within the Person schema after the email paragraph as a "description" (e.g., <p class="clipped" itemprop="description">[your summary here]</p>); however, doing so may result in information being duplicated by bots reading your resume.

Experience

Now we get to the complex portion - work experience - and I'll try to make it as simple as possible. First, the data needs to be wrapped in the "experience" class for the hResume and h-resume formats and since experience is really an ordered list of events, we're going to be semantic and use the OL tag and since they're events, we're going to add the vcalendar class. This means our experience items are wrapped inside code like this...

  <section>
    <header>Experience</header>
    <div class="experience p-experience">
    <ol class="vcalendar">
      [your experience here]
    </ol>
    </div>
  </section>

This means our work experience - each job - can be wrapped in an event, giving us code like this...

<li class="vevent vcard h-event h-card" itemscope itemtype="http://schema.org/Event">
  <a href="#contact-p-name" class="include"></a>
  <div itemprop="organizer" itemscope="" itemtype="http://schema.org/Organization">
    <p class="org p-org" itemprop="name">[your employer]</p>
    <p class="location p-location" itemprop="address" itemscope="" itemtype="http://schema.org/PostalAddress">
      <span class="adr p-adr">
        <span class="locality p-locality" itemprop="addressLocality">[employer locality]</span>
        <abbr class="region p-region" itemprop="addressRegion" title="[region]">[employer region]</abbr>
      </span>
    </p>
  </div>
  <p class="summary p-summary title p-job-title" itemprop="name">[job title]</p>
  <abbr class="dtstart dt-start" content="[start year]-[start month]" itemprop="startDate" title="[starting date]">[starting date]</abbr> - <abbr class="dtend dt-end" content="[end year]-[end month]" itemprop="endDate" title="[ending date]">[ending date]</abbr>
  <div class="description p-description">
    <p itemprop="description">[job description]</p>
  </div>
</li>

There are a few additional things you'll want to know about this section. First, the readers will strip HTML tags out of properties, so don't worry about any markup you have inside the specified properties; however, they do not alter white space - e.g., line breaks, tabs, and spaces - so keep it to a minimum. Second, there are a couple things to note about the dates - the first is that the content and title values are ISO 8601 format and the second is that the starting date is always required for an event but an ending date is not, which means I can easily use a date range like <abbr class="dtstart dt-start" content="2009-03" itemprop="startDate" title="2015-07-01">July 2014</abbr> - <span class="date-name">Present</span> for a current position. Third, you'll notice the very first element within the event is an anchor tag that uses the ID attribute we created in the contact information as its href with the class attibute "include" – this is how we're using "p-name" data we identified earlier.

If I had a second job with the same employer, common practice is to not list the employer information a second time, but we want to make sure our information is as accurate and complete as possible, so we include it and just use the "clipped" class to hide it, like so.

<li class="vevent vcard h-event h-card" itemscope itemtype="http://schema.org/Event">
  <a href="#contact-p-name" class="include"></a>
  <div class="clipped" itemprop="organizer" itemscope="" itemtype="http://schema.org/Organization">
    <p class="org p-org" itemprop="name">[your employer]</p>
    <p class="location p-location" itemprop="address" itemscope="" itemtype="http://schema.org/PostalAddress">
      <span class="adr p-adr">
        <span class="locality p-locality" itemprop="addressLocality">[employer locality]</span>
        <abbr class="region p-region" itemprop="addressRegion" title="[region]">[employer region]</abbr>
      </span>
    </p>
  </div>
  <p class="summary p-summary title p-job-title" itemprop="name">[job title]</p>
  <abbr class="dtstart dt-start" content="[start year]-[start month]" itemprop="startDate" title="[starting date]">[starting date]</abbr> - <abbr class="dtend dt-end" content="[end year]-[end month]" itemprop="endDate" title="[ending date]">[ending date]</abbr>
  <div class="description p-description">
    <p itemprop="description">[job description]</p>
  </div>
</li>

Education

The next section is typically education. Again, we're going to use the event model to describe this portion of your career. Like the experience section, it needs to be wrapped in section description and is an ordered list, so...

<section>
  <header>Education</header>
  <div class="education p-education">
    <ol class="vcalendar">
      [your education events here]
    </ol>
  </div>
</section>

The name or description should contain a short description of the event. If you're listing a single course, it would be the course name, but if you're listing all the courses leading up to matriculation, list the degree or certificate you earned, like so.
<li class="vevent h-event" itemscope="" itemtype="http://schema.org/Event">
  <div class="summary p-summary vcard h-card" itemprop="organizer" itemscope="" itemtype="http://schema.org/Organization">
    <a class="url fn p-name org p-org" href="http://www.millikin.edu/" itemprop="name">[institution]</a>
    <p class="adr p-adr" itemprop="address" itemscope="" itemtype="http://schema.org/PostalAddress">
      <span class="locality p-locality" itemprop="addressLocality">[locality]</span>
      <abbr class="region p-region" itemprop="addressRegion" title="[region]">[region]</abbr>
    </p>
  </div>
  <abbr class="dtstart dt-start" content="[start year]-[start month]" itemprop="startDate" title="[starting date]">[starting date]</abbr> - <abbr class="dtend dt-end" content="[end year]-[end month]" itemprop="endDate" title="[ending date]">[ending date]</abbr>
  <p class="description p-description" itemprop="name">[degree, program of study, or course name]</p>
</li>

As with the section containing work experience, the bots will strip HTML tags out of properties and leave white space, the dates use ISO 8601 format in the content attribute, and the starting date is required but an ending date is not. Unlike the work experience, we are not including an anchor tag that uses the ID attribute we created in the contact information as its href with the class attibute "include" as the first element – the h-card entry is that of the institution instead.

Skills

The final section I'll cover in detail is the section listing your skills. This section does not use microdata because there isn't currently a schema for skills, with the exception of as a property of the JobPosting schema. There are other sections typically included in a CV, and one of those sections Note 9 is included in the hResume and h-resume formats, but those are not discussed in any detail here.

Because information about skills is typically something for which people generally request additional information, I recommend that you use a table as markup. Use the class name "skills" for the table, this will identify the section, and use the class names "skill" (for hResume) and "p-skill" for h-resume to identify individual skills. I recommend that you add columns to your table to identify when you last used the skill or what your competency level is - the latter is especially use for language skills. This approach would give us something like the following.

<section>
  <header>Skills</header>
  <table class="skills">
    <thead>
      <tr><th>Skill</th><th>Last Used</th></tr>
    </thead>
    <tbody>
      <tr><td class="skill p-skill">AJAX/XmlHttpRequest</td><td>2014</td></tr>
      <tr><td class="skill p-skill">bootstrap</td><td>2014</td></tr>
      <tr><td class="skill p-skill">CSS/CSS3</td><td>2014</td></tr>
      <tr><td class="skill p-skill">cssless</td><td>2014</td></tr>
      <tr><td class="skill p-skill">D3js</td><td>2014</td></tr>
      <tr><td class="skill p-skill">dustjs</td><td>2014</td></tr>
      <tr><td class="skill p-skill">git</td><td>2014</td></tr>
      <tr><td class="skill p-skill">HTML/HTML5</td><td>2014</td></tr>
      <tr><td class="skill p-skill">Java</td><td>2014</td></tr>
      <tr><td class="skill p-skill">JavaScript</td><td>2014</td></tr>
      <tr><td class="skill p-skill">jQuery</td><td>2014</td></tr>
      <tr><td class="skill p-skill">JSON</td><td>2014</td></tr>
      <tr><td class="skill p-skill">nodejs</td><td>2014</td></tr>
      <tr><td class="skill p-skill">Perl</td><td>2014</td></tr>
      <tr><td class="skill p-skill">Splunk</td><td>2014</td></tr>
      <tr><td class="skill p-skill">SVN</td><td>2014</td></tr>
      <tr><td class="skill p-skill">XML-Schema</td><td>2014</td></tr>
      <tr><td class="skill p-skill">XML</td><td>2014</td></tr>
      <tr><td class="skill p-skill">XPath</td><td>2014</td></tr>
      <tr><td class="skill p-skill">YUI</td><td>2014</td></tr>
    </tbody>
  </table>
</section>

Other Sections

Because other sections typically found in a resume – e.g., "publications", "presentations", or "honors and awards" – are events, you may wish to mark them up as microdata or h-event to include them; however, they are not recognized by either resume format at this time.

Progressive Enhancement – Printing and Sorting Data

One final suggestion - by creating not only a browser stylesheet but a print stylesheet as well, you can easily make one resource fit two purposes, and that is easily done using the "@media print" query. Use of the "print" stylesheet enables you to control page breaks and typography for print versions of your resume, as well as giving you the ability to hide elements in the page that might detract from your resume.

You can also extend the functionality embedded in the browser version of your resume using JavaScript to make your resume dynamic. For example, you may wish to use the cjl-scrollabletable.js library to make your skills (or affiliations) table take up less real-estate and also allow the user to sort the data by the different columns.

If you'd like to see how all this works together, feel free to look at a full resume marked up at http://www.cathmhaol.com/resume.htm as an example.

Notes and references

Links in the notes and references list open in a new window
  1. A simple way to express meaning on the web in HTML without further complex XML alternatives.
  2. A simple, open format for publishing information about people and organizations using a 1:1 representation of the VCARD (RFC 2426) properties and values in HTML.
  3. An intentional hidden feature or message in a work such as a computer program, video game, movie, book, or crossword.
  4. This concept is the Semantic Web that Tim Berners-Lee has pushed for a number of years, even basing a TED talk around it.
  5. The hResume microformat, and its successor – h-resume – is a microformat for publishing resumes and CVs.
  6. Microdata schemas are methods used to markup HTML pages in ways recognized by major search providers, and that can also be used for structured data interoperability
  7. The specific elements used with the h-resume format, and some simple examples, can be found at http://microformats.org/wiki/h-resume. The h-card format, used to mark up contact information, can be found at http://microformats.org/wiki/h-card.
  8. The specific elements used in marking up contact information using microdata can be found at http://schema.org/Person and http://schema.org/PostalAddress.
  9. A section listing "affiliations" is recognized by both the hResume and h-resume formats; however, since there is not a microdata resume format, affiliations are contained by the Person schema. As with the "summary" section, you may wish to list affiliations with the Person information; however that may result in duplicate information.

No comments:

Post a Comment