[@IndeedEng] Building Indeed Resume Search

4,316 views

Published on

Video available: http://youtu.be/qcnP5gQGBaU

Software engineer David Tulig will dive into the architecture of Indeed’s Resume Instant Search and our use of the Google Closure tools. David will explain how we write maintainable, efficient JavaScript components for Resume Instant Search and other Indeed products. He will discuss how we create templates that run on both client and server, providing fast initial page load time and search engine-friendly pages with the responsiveness of client-side rendering.

Speaker:

David Tulig is a software engineer on the Job Search team at Indeed. David has worked on employer, resume, and job search products during his 4 years at Indeed.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,316
On SlideShare
0
From Embeds
0
Number of Embeds
2,833
Actions
Shares
0
Downloads
53
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

[@IndeedEng] Building Indeed Resume Search

  1. 1. Building Indeed Resume Search David Tulig
  2. 2. DAVID TULIG TECH LEAD JOB SEARCH TEAM
  3. 3. I help people get jobs.
  4. 4. Jobseekers Job
  5. 5. Jobseekers Job
  6. 6. We learned from Job Search
  7. 7. The web evolved
  8. 8. PRINCIPLES Simple Fast Comprehensive Relevant
  9. 9. PRINCIPLES Simple Fast Comprehensive Relevant
  10. 10. GOALS
  11. 11. Responsive user experience
  12. 12. javas
  13. 13. javas javascript javascript jquery javascript html javascript html css
  14. 14. javascript javascript javascript jquery javascript html javascript html css
  15. 15. Maintainable code
  16. 16. Re-usable components
  17. 17. Separate presentation and logic
  18. 18. Fast
  19. 19. GOALS Responsive UX Maintainable code Fast
  20. 20. Library support
  21. 21. Google Closure Tools
  22. 22. Closure Library
  23. 23. array asserts async color crypt cssom date disposable dom ds editor events format functions fx gears global graphics history i18n iter json locale math messaging module net positioning proto proto2 pubsub result soy spell stats storage string structs style testing text tweak ui userAgent vec
  24. 24. array asserts async color crypt cssom date disposable dom ds editor events format functions fx gears global graphics history i18n iter json locale math messaging module net positioning proto proto2 pubsub result soy spell stats storage string structs style testing text tweak ui userAgent vec
  25. 25. Modular and independent
  26. 26. Application dom events style
  27. 27. Application dom events style arrayobject
  28. 28. Application dom events style arrayobject string
  29. 29. Application dom events style arrayobject string
  30. 30. Application dom events style arrayobject string
  31. 31. Application dom events style array object string
  32. 32. goog.provide('indeed.Search'); goog.require('goog.dom'); goog.require('goog.events'); /* Search */ indeed.Search.validateLocation = function() {...};
  33. 33. goog.provide('indeed.Search'); goog.require('goog.dom'); goog.require('goog.events'); /* Search */ indeed.Search.validateLocation = function() {...};
  34. 34. Application dom events style arrayobject string
  35. 35. Unit testing
  36. 36. Closure Templates
  37. 37. Closure Compiler
  38. 38. whitespace_only
  39. 39. simple_optimizations
  40. 40. advanced_optimizations
  41. 41. Type checking
  42. 42. Unused code removal
  43. 43. /** Alias for getElementById. If a DOM node is passed in then we just return */ goog.dom.getElement = function(element) {...}; /** Looks up elements by both tag and class name, using browser native functions */ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {...}; /** Returns an array of all the elements with the provided className. */ goog.dom.getElementsByClass = function(className, opt_el) {...}; /** Returns the first element with the provided className. */ goog.dom.getElementByClass = function(className, opt_el) {...}; /** Alias for getElementById. If a DOM node is passed in then we just return */ goog.dom.getElement = function(element) {...}; /** Looks up elements by both tag and class name, using browser native functions */ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {...}; /** Returns the first element with the provided className. */ goog.dom.getElementByClass = function(className, opt_el) {...};
  44. 44. /** Alias for getElementById. If a DOM node is passed in then we just return */ goog.dom.getElement = function(element) {...}; /** Looks up elements by both tag and class name, using browser native functions */ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {...}; /** Returns an array of all the elements with the provided className. */ goog.dom.getElementsByClass = function(className, opt_el) {...}; /** Returns the first element with the provided className. */ goog.dom.getElementByClass = function(className, opt_el) {...}; /** Alias for getElementById. If a DOM node is passed in then we just return */ goog.dom.getElement = function(element) {...}; /** Looks up elements by both tag and class name, using browser native functions */ goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {...}; /** Returns the first element with the provided className. */ goog.dom.getElementByClass = function(className, opt_el) {...};
  45. 45. /** Alias for getElementById. If a DOM node is passed in then we just return */ goog.dom.getElement = function(element) {...}; /** Returns an array of all the elements with the provided className. */ goog.dom.getElementsByClass = function(className, opt_el) {...};
  46. 46. Aggressive renaming
  47. 47. Let's build Resume Search
  48. 48. Resume Search architecture
  49. 49. Browser Server q=javasc
  50. 50. Browser Server q=javasc { "suggestions" : [ "javascript", "javascript jquery", "javascript html", "javascript html css", "javascript ajax" ] }
  51. 51. AutoComplete AutoComplete
  52. 52. Search
  53. 53. Preview
  54. 54. Autocomplete Search Preview
  55. 55. Location Autocomplete Search Preview Query Autocomplete A Possible Approach: Tightly Coupled Modules
  56. 56. Use events
  57. 57. { "suggestions" : [ "javascript", "javascript jquery", "javascript html", "javascript html css", "javascript ajax" ] }
  58. 58. Autocomplete Text Handler Drop Down Handler RPC Handler
  59. 59. Autocomplete Text Handler Drop Down Handler RPC Handler
  60. 60. Autocomplete Text Handler Drop Down Handler RPC Handler 1.New text"javasc"
  61. 61. Autocomplete Text Handler Drop Down Handler RPC Handler2.Getsuggestions
  62. 62. Autocomplete Text Handler Drop Down Handler RPC Handler3.Suggestions
  63. 63. Autocomplete Text Handler Drop Down Handler RPC Handler 4.Render
  64. 64. Autocomplete Text Handler Drop Down Handler RPC Handler 6.Clickon"javascript"
  65. 65. Autocomplete Text Handler Drop Down Handler RPC Handler 6.Settextto "javascript"
  66. 66. Search App AutoComplete Text Handler Drop Down Handler Search RPC Handler
  67. 67. Search App AutoComplete Text Handler Drop Down Handler Search RPC Handler Awesome
  68. 68. Search App AutoComplete Text Handler Drop Down Handler Search RPC Handler
  69. 69. Search App AutoComplete Text Handler Drop Down Handler Search RPC Handler
  70. 70. Search App AutoComplete Text Handler Drop Down Handler Search RPC Handler
  71. 71. User interface
  72. 72. Templates
  73. 73. Server or client?
  74. 74. indeed.com/resumes?q=java
  75. 75. indeed.com/resumes?q=java HTML Time
  76. 76. indeed.com/resumes?q=java LOAD JSHTML Time
  77. 77. indeed.com/resumes?q=java AJAX RESULTSLOAD JSHTML
  78. 78. indeed.com/resumes?q=java JS REQ JS RESP AJAX REQ AJAX RESPHTML + DATA AJAX RESULTSLOAD JS Time
  79. 79. indeed.com/resumes?q=java JS REQ JS RESPHTML + DATA LOAD JS
  80. 80. indeed.com/resumes?q=java HTML + RESULTS Time
  81. 81. indeed.com/resumes?q=java HTML + RESULTS JS REQ JS RESPLOAD JS
  82. 82. indeed.com/resumes?q=java HTML + RESULTS JS RESPLOAD JS
  83. 83. Server or client?
  84. 84. Server AND client!
  85. 85. Don't repeat yourself
  86. 86. Closure Templates
  87. 87. template.soy Closure Template Compilernew TofuRenderer() template.js one template. all requests.
  88. 88. /resumes?q=javascript Server Rendering
  89. 89. /resumes?q=javascript Server Rendering Controller
  90. 90. /resumes?q=javascript Controller Model Server Rendering
  91. 91. /resumes?q=javascript Controller Model new TofuRenderer() Server Rendering
  92. 92. /resumes?q=javascript Controller Model new TofuRenderer() HTML Server Rendering
  93. 93. /instant?q=javascriptClient Rendering
  94. 94. /instant?q=javascript Controller Client Rendering
  95. 95. /instant?q=javascript Controller Model Client Rendering
  96. 96. /instant?q=javascript Controller Model JSON Client Rendering
  97. 97. /instant?q=javascript Controller Model template.js JSON Client Rendering
  98. 98. /instant?q=javascript Controller Model template.js JSON Client Rendering HTML
  99. 99. /resumes?q=javascript /instant?q=javascript Controller Model new TofuRenderer() HTML template.js JSON
  100. 100. Don't repeat yourself
  101. 101. Application
  102. 102. Application Browser
  103. 103. Library Browser
  104. 104. Library Browser Templates
  105. 105. Library Browser Templates Application
  106. 106. HTML LIBRARY TEMPLATES APPLICATION Time
  107. 107. COMBINED Time HTML
  108. 108. COMPILED Time HTML
  109. 109. Application size
  110. 110. whitespace_only 126k
  111. 111. whitespace_only 126k simple_optimizations 108k
  112. 112. whitespace_only 126k simple_optimizations 108k 49k advanced_optimizations
  113. 113. RESUME SEARCH Re-usable components Responsive UX Fast initial load
  114. 114. [video of http://www.indeed.com/resumes]
  115. 115. We learned from Resume Search
  116. 116. jobsearch.js
  117. 117. jobsearch.js 41k
  118. 118. jobsearch.js 41k jobsearch_v2.js 35k
  119. 119. 6K MATTERS
  120. 120. 6K MATTERS 6k reduction
  121. 121. 6K MATTERS 6k reduction 546 GB / month
  122. 122. 6K MATTERS 6k reduction 546 GB / month 428 hours / month
  123. 123. david tulig twitter: @dtulig indeed.com/resumes engineering.indeed.com

×