├── .gitignore ├── schedule ├── code-excerpts │ ├── bad-code.md │ ├── routes.md │ └── geiger-counter.md ├── w2.md ├── w3.md ├── w4.md ├── w7.md └── questions │ ├── w2 │ ├── w2b.md │ └── w2a.md │ ├── w3 │ ├── w3a.md │ └── w3b.md │ ├── w7 │ ├── w7b.md │ └── w7a.md │ └── w4 │ ├── w4a.md │ └── w4b.md ├── documents └── default-email.txt ├── README.md └── pairs.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | curriculum-stash 4 | dist 5 | -------------------------------------------------------------------------------- /schedule/code-excerpts/bad-code.md: -------------------------------------------------------------------------------- 1 | # Bad Code 2 | 3 | ``` ruby 4 | class CommentsController < ApplicationController 5 | def users_comments 6 | posts = Post.all 7 | comments = posts.map(&:comments).flatten 8 | @user_comments = comments.select do |comment| 9 | comment.author.username == params[:username] 10 | end 11 | end 12 | end 13 | ``` 14 | -------------------------------------------------------------------------------- /schedule/code-excerpts/routes.md: -------------------------------------------------------------------------------- 1 | # Routes 2 | 3 | ``` 4 | GET /cats 5 | GET /cats/:id 6 | GET /cats/new 7 | POST /cats 8 | GET /cats/:id/edit 9 | PATCH /cats/:id 10 | PUT /cats/:id 11 | DELETE /cats/:id 12 | GET /cats/:cat_id/tricks 13 | POST /cats/:cat_id/tricks 14 | DELETE /cats/:cat_id/tricks/:id 15 | POST /cats/:cat_id/upvote 16 | DELETE /cats/:cat_id/upvote 17 | ``` 18 | -------------------------------------------------------------------------------- /schedule/w2.md: -------------------------------------------------------------------------------- 1 | # Week 2 2 | 3 | ** ONLY READ THE QUESTIONS THAT YOU ARE ASSIGNED TO ASK. ** 4 | 5 | ## Assignments 6 | 7 | * If you are student A, go [here][student-a]. 8 | * If you are student B, go [here][student-b]. 9 | 10 | ## Grading Sheet 11 | 12 | [Here][grading-sheet] is a link to the grading sheet. 13 | 14 | [student-a]: ./questions/w2/w2a.md 15 | [student-b]: ./questions/w2/w2b.md 16 | [grading-sheet]: https://docs.google.com/spreadsheets/d/17KhZzPX8oysrbw7a4z4Z8huayaaTStUWjdRle3nmLC0/edit?usp=sharing 17 | -------------------------------------------------------------------------------- /schedule/w3.md: -------------------------------------------------------------------------------- 1 | # Week 3 2 | 3 | ** ONLY READ THE QUESTIONS THAT YOU ARE ASSIGNED TO ASK. ** 4 | 5 | ## Assignments 6 | 7 | * If you are student A, go [here][student-a]. 8 | * If you are student B, go [here][student-b]. 9 | 10 | ## Grading Sheet 11 | 12 | [Here][grading-sheet] is a link to the grading sheet. 13 | 14 | [student-a]: ./questions/w3/w3a.md 15 | [student-b]: ./questions/w3/w3b.md 16 | [grading-sheet]: https://docs.google.com/spreadsheets/d/17KhZzPX8oysrbw7a4z4Z8huayaaTStUWjdRle3nmLC0/edit?usp=sharing 17 | -------------------------------------------------------------------------------- /schedule/w4.md: -------------------------------------------------------------------------------- 1 | # Week 4 2 | 3 | ** ONLY READ THE QUESTIONS THAT YOU ARE ASSIGNED TO ASK. ** 4 | 5 | ## Assignments 6 | 7 | * If you are student A, go [here][student-a]. 8 | * If you are student B, go [here][student-b]. 9 | 10 | ## Grading Sheet 11 | 12 | [Here][grading-sheet] is a link to the grading sheet. 13 | 14 | [student-a]: ./questions/w4/w4a.md 15 | [student-b]: ./questions/w4/w4b.md 16 | [grading-sheet]: https://docs.google.com/spreadsheets/d/17KhZzPX8oysrbw7a4z4Z8huayaaTStUWjdRle3nmLC0/edit?usp=sharing 17 | -------------------------------------------------------------------------------- /schedule/w7.md: -------------------------------------------------------------------------------- 1 | # Week 7 2 | 3 | ** ONLY READ THE QUESTIONS THAT YOU ARE ASSIGNED TO ASK. ** 4 | 5 | ## Assignments 6 | 7 | * If you are student A, go [here][student-a]. 8 | * If you are student B, go [here][student-b]. 9 | 10 | ## Grading Sheet 11 | 12 | [Here][grading-sheet] is a link to the grading sheet. 13 | 14 | [student-a]: ./questions/w7/w7a.md 15 | [student-b]: ./questions/w7/w7b.md 16 | [grading-sheet]: https://docs.google.com/spreadsheets/d/17KhZzPX8oysrbw7a4z4Z8huayaaTStUWjdRle3nmLC0/edit?usp=sharing 17 | -------------------------------------------------------------------------------- /documents/default-email.txt: -------------------------------------------------------------------------------- 1 | Hi all, 2 | 3 | Below you will find the link to today’s whiteboarding questions. Click the link that is in the column that has your name. 4 | 5 | Spend ten minutes reviewing the questions you will ask. Each candidate should have about 35 minutes to answer both questions. Give yourself about 5 to 10 minutes to fill out the scorecard. 6 | 7 | Whiteboarding should be finished around 11:00am. If you happen to finish early, feel free to get started on the day’s work. 8 | 9 | Here are the assignments: 10 | 11 | Whiteboarding Assignments 12 | 13 | Here is the whiteboarding grading sheet: 14 | 15 | Whiteboarding Grading Sheet 16 | 17 | Have fun! 18 | 19 | Louis 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **NOTE** : This is a deprecated repo. See [whiteboarding](https://github.com/appacademy/whiteboarding) for an updated whiteboarding curriculum. 2 | 3 | # Curriculum Whiteboarding 4 | 5 | This repository exists to organize the whiteboard questions that 6 | students are given during the first nine weeks of the curriculum. 7 | 8 | ## Schedule 9 | 10 | There are four whiteboarding sessions that occur during the curriculum. 11 | 12 | * [Week 2][w2] (W2D2) 13 | * [Week 3][w3] (W3D2) 14 | * [Week 4][w4] (W4D3) 15 | * [Week 7][w7] (W7D3) 16 | 17 | [w2]: ./schedule/w2.md 18 | [w3]: ./schedule/w3.md 19 | [w4]: ./schedule/w4.md 20 | [w7]: ./schedule/w7.md 21 | 22 | ## Instructors 23 | 24 | Instructor can view the old Google Drive [here][google-drive]. 25 | 26 | [google-drive]: https://drive.google.com/drive/u/1/folders/0B2GA4obf3HcmbkUyU2d0RVRGdjA 27 | -------------------------------------------------------------------------------- /schedule/questions/w2/w2b.md: -------------------------------------------------------------------------------- 1 | # Week 2 2 | 3 | ## Student B 4 | 5 | Below are the two questions that you will be asking student A. 6 | 7 | ### Fibonacci – Two Ways 8 | 9 | #### Prompt 10 | 11 | Write a method, `fibs(num)` which returns the first `num` elements from 12 | the Fibonacci sequence, given `num`. 13 | 14 | Solve it both iteratively and recursively. 15 | 16 | #### Solution 17 | 18 | Iterative Solution: 19 | 20 | ```ruby 21 | def fibs(num) 22 | return [] if num == 0 23 | return [0] if num == 1 24 | 25 | fibs = [0, 1] 26 | while fibs.count < num 27 | fibs << fibs[-1] + fibs[-2] 28 | end 29 | 30 | fibs 31 | end 32 | ``` 33 | 34 | Recursive Solution: 35 | 36 | ```ruby 37 | def fibs(num) 38 | return [] if num == 0 39 | return [0] if num == 1 40 | return [0, 1] if num == 2 41 | 42 | prev_fibs = fibs(num - 1) 43 | prev_fibs << prev_fibs[-1] + prev_fibs[-2] 44 | 45 | prev_fibs 46 | end 47 | ``` 48 | 49 | ### Agile 50 | 51 | #### Prompt 52 | 53 | Define "Test-Driven Development" and "Continuous Integration." Also, 54 | what are their benefits? 55 | 56 | #### Solution 57 | 58 | Test-Driven Development follows the pattern of writing tests first, 59 | watching them fail, writing the code to make them pass, and then 60 | watching the tests pass. 61 | 62 | Continuous Integration is the practice of integrating newly developed 63 | code back into a main branch multiple times a day. 64 | 65 | A benefit of Test-Driven Development is that it allows for clear 66 | expectations of the code to be written. Another benefit is that it 67 | allows for safer refactoring. After refactoring, a developer can be much 68 | more certain that the refactoring did not introduce any bugs. 69 | 70 | A benefit of Continuous Integration is that it prevents the need to 71 | reconcile massive merge conflicts, which can be fairly common if 72 | multiple developers work on multiple feature branches simultaneously. 73 | -------------------------------------------------------------------------------- /schedule/questions/w3/w3a.md: -------------------------------------------------------------------------------- 1 | # Week 3 2 | 3 | ## Student A 4 | 5 | Below are the two questions that you will be asking student B. 6 | 7 | ### OOP – Jukebox 8 | 9 | #### Prompt 10 | 11 | Design a musical jukebox using object-oriented principles. 12 | 13 | #### Solution 14 | 15 | Here are some answers to questions the interviewee might ask: 16 | 17 | ##### Is the jukebox physical or virtual? 18 | 19 | Assume the jukebox is virtual or computer-simulated. 20 | 21 | ##### Does the jukebox accept currency? 22 | 23 | Assume the jukebox operates free of charge. 24 | 25 | Here is the skeleton of a potential solution: 26 | 27 | ```ruby 28 | class Jukebox 29 | attr_accessor :user 30 | attr_reader :current_track 31 | 32 | def initialize(player, user) 33 | @player = player 34 | @user = user 35 | @current_track = nil 36 | end 37 | end 38 | 39 | class Player 40 | attr_accessor :album, :playlist 41 | 42 | def initialize(album, playlist) 43 | @album = album 44 | @playlist = playlist 45 | end 46 | 47 | def play_track(track) 48 | # Begin playing... 49 | end 50 | end 51 | 52 | class Playlist 53 | def initialize 54 | @queue = [] 55 | end 56 | 57 | def add_track(track) 58 | @queue.push(track) 59 | end 60 | 61 | def shift 62 | @queue.shift 63 | end 64 | end 65 | 66 | class Album 67 | # Information about the album 68 | end 69 | 70 | class Track 71 | # Information about the track, including album 72 | end 73 | 74 | class User 75 | # Information about the user. 76 | end 77 | ``` 78 | 79 | ### SQL – Employees 80 | 81 | #### Prompt 82 | 83 | In a SQL db, you have two tables, an employees table and a departments 84 | table. Employees belong to only one department. Write a SQL query that, 85 | given a department name, finds all the employees in that department. 86 | 87 | #### Solution 88 | 89 | ```sql 90 | SELECT 91 | employees.* 92 | FROM 93 | employees e 94 | JOIN 95 | departments d ON e.department_id = d.id 96 | WHERE 97 | d.name = ? 98 | ``` 99 | -------------------------------------------------------------------------------- /schedule/code-excerpts/geiger-counter.md: -------------------------------------------------------------------------------- 1 | # Geiger Counter 2 | 3 | ```js 4 | import React from 'react'; 5 | 6 | class GeigerCounter extends React.Component { 7 | constructor() { 8 | this.state = { 9 | counts: [false], 10 | probability: 50, 11 | maxCountsSize: this.props.maxCountsSize || 30, 12 | }; 13 | } 14 | 15 | componentDidMount() { 16 | this.startCounter(); 17 | } 18 | 19 | startCounter() { 20 | setInterval(() => { 21 | this.updateCounts(); 22 | }, 1000); 23 | } 24 | 25 | updateCounts() { 26 | const booleanVal = this.generateBoolean(); 27 | 28 | const newCounts; 29 | 30 | if (this.state.counts.length < this.state.maxCountsSize) { 31 | newCounts = this.state.counts.concat(booleanVal); 32 | } else { 33 | newCounts = this.state.counts.slice(1).concat(booleanVal); 34 | } 35 | 36 | this.setState({ counts: newCounts }); 37 | console.log(this.state.counts.length); 38 | } 39 | 40 | generateBoolean() { 41 | const floatProbability = this.state.probability / 100.0; 42 | const randFloat = Math.random(); 43 | 44 | return randFloat < floatProbability; 45 | } 46 | 47 | geigerValue() { 48 | const { length } = this.state.counts; 49 | 50 | let trueCount = 0; 51 | 52 | for (let i = 0; i < length; i++) { 53 | if (this.state.counts[i]) trueCount++; 54 | } 55 | 56 | return trueCount / length; 57 | } 58 | 59 | updateProbability(value) { 60 | const newValue = this.state.probability + value; 61 | if (newValue >= 0 && newValue <= 100) { 62 | this.setState({ probability: newValue }); 63 | } 64 | } 65 | 66 | render() { 67 | return ( 68 |
69 |

70 | The radiation level is currently: {this.geigerValue()} 71 |

72 | 73 | The current radiation level is at {this.state.probability}% 74 | 75 | 76 |
77 | 78 | 79 | 80 |
81 | ); 82 | } 83 | } 84 | ``` 85 | -------------------------------------------------------------------------------- /schedule/questions/w2/w2a.md: -------------------------------------------------------------------------------- 1 | # Week 2 2 | 3 | ## Student A 4 | 5 | Below are the two questions that you will be asking student B. 6 | 7 | ### Recursive Sum 8 | 9 | #### Prompt 10 | 11 | Write a function that takes an array of integers and returns their sum. 12 | Use recursion. 13 | 14 | #### Solution 15 | 16 | ```ruby 17 | def sum_rec(nums) 18 | return 0 if nums.empty? 19 | nums[0] + sum_rec(nums.drop(1)) 20 | end 21 | ``` 22 | 23 | ### Ruby – Contrast and Compare 24 | 25 | #### Prompt 26 | 27 | Ruby is a dynamic, reflective language that lends itself to 28 | object-oriented programming. What are some benefits and drawbacks of 29 | dynamic languages? What are some benefits and drawbacks of reflection 30 | and object-oriented programming? 31 | 32 | #### Solution 33 | 34 | This question has a wide variety of potential answers. 35 | 36 | Benefits of dynamic languages: 37 | 38 | * Allows for execution of code at compile time 39 | * Potentially more abstraction and less code 40 | * Dynamic typing allows for flexibility 41 | 42 | Drawbacks of dynamic languages: 43 | 44 | * Dynamic typing means that errors are often encountered at run time 45 | * Run time evaluation decreases execution speed 46 | 47 | Benefits of reflection: 48 | 49 | * It allows for much of metaprogramming 50 | * Create custom methods on the fly 51 | 52 | Drawbacks of reflection: 53 | 54 | * Code can be very confusing/hard to reason about 55 | 56 | Benefits of object-oriented programming: 57 | 58 | * Inheritance lends itself to easy reusability of code 59 | * Encapsulation offers a system for organization of code 60 | * Information hiding ensures that objects have enough information to 61 | perform what they need to do without making that information public to 62 | external objects 63 | 64 | Drawbacks of object-oriented programming: 65 | 66 | * The preference for data over functions can result in more code 67 | * Polymorphism and inheritance can make it difficult to determine what 68 | the result of a method call will be 69 | * Reliance on side effects can make it difficult to reason about the 70 | correctness of code (to work out correctly, methods might need to be 71 | called in a certain order or objects might need to be in some certain 72 | state) 73 | -------------------------------------------------------------------------------- /pairs.js: -------------------------------------------------------------------------------- 1 | const FIRST = 'FIRST'; 2 | const SECOND = 'SECOND'; 3 | const ODD = 'ODD'; 4 | const EVEN = 'EVEN'; 5 | 6 | const getPodWrappers = () => { 7 | const podWrappers = document.querySelectorAll('section.pod-tables'); 8 | return Array.from(podWrappers); 9 | } 10 | 11 | const getPairNameWrappers = (parent = document) => { 12 | const nameWrappers = parent.querySelectorAll('figure.pair-selects'); 13 | return Array.from(nameWrappers); 14 | } 15 | 16 | const getAllStudents = (parent = document) => { 17 | const studentNameWrappers = parent.querySelectorAll('h4.student-name'); 18 | return Array.from(studentNameWrappers); 19 | } 20 | 21 | const getAllStudentNames = (n) => { 22 | const pairNameWrappers = getPairNameWrappers(); 23 | let names = []; 24 | pairNameWrappers.forEach((wrapper) => { 25 | const nameStrings = getAllStudents(wrapper).map((el) => { 26 | return el.innerHTML.trim(); 27 | }); 28 | nameStrings.forEach((name) => { 29 | names.push(name); 30 | }); 31 | if (nameStrings.length < 2) { 32 | names.push('empty'); 33 | } 34 | }); 35 | const filteredNames = names.filter((val, idx) => { 36 | if (n === ODD) { 37 | return idx % 2 !== 0; 38 | } else if (n === EVEN) { 39 | return idx % 2 === 0; 40 | } 41 | }) 42 | const namesString = filteredNames.join('\n'); 43 | 44 | return namesString; 45 | } 46 | 47 | const getStudents = (index) => { 48 | const allStudentNames = getAllStudentNames(); 49 | let studentNames; 50 | switch (index) { 51 | case FIRST: 52 | studentNames = getAllStudentNames(EVEN); 53 | console.log(studentNames); 54 | return; 55 | case SECOND: 56 | studentNames = getAllStudentNames(ODD); 57 | console.log(studentNames); 58 | return; 59 | default: 60 | throw 'Invalid Index'; 61 | }; 62 | } 63 | 64 | // Use this script to get the first row of names 65 | const getFirstStudents = () => { 66 | const students = getStudents(FIRST); 67 | } 68 | 69 | // Use this script to get the second row of names 70 | const getSecondStudents = () => { 71 | const students = getStudents(SECOND); 72 | } 73 | 74 | // Use this script to get the pods 75 | const getPodNames = () => { 76 | const podWrappers = getPodWrappers(); 77 | let result = ''; 78 | podWrappers.forEach((pod) => { 79 | const name = pod.querySelector('h2').innerHTML.trim(); 80 | const numPairs = getPairNameWrappers(pod).length; 81 | for (let i = 0; i < numPairs; i += 1) { 82 | result += `${name}\n`; 83 | } 84 | }); 85 | console.log(result); 86 | } 87 | 88 | // INSTRUCTIONS: 89 | // 90 | // Get all the first students with `getFirstStudents()`. 91 | // Get all the second students with `getSecondStudents()`. 92 | // Get their pod names with `getPodNames()`. 93 | // 94 | // Like as follows: 95 | // 96 | // getFirstStudents(); 97 | // getSecondStudents(); 98 | // getPodNames(); 99 | -------------------------------------------------------------------------------- /schedule/questions/w7/w7b.md: -------------------------------------------------------------------------------- 1 | # Week 7 2 | 3 | ## Student B 4 | 5 | Below are the two questions that you will be asking student A. 6 | 7 | ### Redux 8 | 9 | #### Prompt 10 | 11 | I want a simple social media app that will store posts. 12 | I would like you to use Redux to store the front-end state. 13 | Each post should have a body, title, and id. 14 | Users should be able to post new posts. 15 | They should also be able to delete old posts and edit existing posts. 16 | Please describe how you would store and work with posts on the front-end 17 | using Redux. In particular, 18 | 19 | * Describe the Redux state shape you would implement 20 | * Describe the reducers and action creators you would use 21 | 22 | #### Solution 23 | 24 | The state should look something like this: 25 | 26 | ```js 27 | { 28 | todos { 29 | 1: { 30 | id: 1, 31 | title: 'A Post', 32 | body: 'It\'s body' 33 | }, 34 | 2: { 35 | id: 2, 36 | title: 'Another Post', 37 | body: 'It also has a body' 38 | }, 39 | } 40 | } 41 | ``` 42 | 43 | In particular, the posts should be stored in an object nested under its 44 | Id. They should not be stored in an array (because we will want constant 45 | time lookup). 46 | 47 | The action creators should look something like this: 48 | 49 | ```js 50 | export const ReceivePosts = posts => ({ 51 | type: RECEIVE_POSTS, 52 | posts 53 | }); 54 | 55 | export const ReceivePost = post => ({ 56 | type: RECEIVE_POST, 57 | post 58 | }); 59 | 60 | // This action creator should NOT take post as an argument 61 | // The id is enough to identify the post to be deleted, and we always 62 | // want our actions to cary the smallest possible payload 63 | export const DeletePost = id => ({ 64 | type: DELETE_POST, 65 | id 66 | }); 67 | ``` 68 | 69 | We will only need one reducer. 70 | The following reducer would work with the above actions: 71 | 72 | ```js 73 | // It is important to remember the default state, in this case: {} 74 | export default function(state = {}, action) { 75 | Object.freeze(state); 76 | switch (action.type) { 77 | case RECEIVE_POSTS: 78 | return action.posts; 79 | case RECEIVE_POST: 80 | // Make sure the post is nested under its Id before merging with state 81 | return Object.assign({}, state, { [action.post.id]: action.post }); 82 | case DELETE_POST: 83 | let newState = Object.assign({}, state); 84 | delete newState[action.id]; 85 | return newState; 86 | default: 87 | return state; 88 | } 89 | } 90 | ``` 91 | 92 | ### React – Virtual DOM 93 | 94 | #### Prompt 95 | 96 | What is React’s virtual DOM and why is it used? How does the diffing 97 | algorithm work? 98 | 99 | #### Solution 100 | 101 | The virtual DOM is a simpler and faster abstraction of the HTML DOM. 102 | While it might be more expensive to manage two DOMs in some respects, 103 | being able to traverse and perform operations on the virtual DOM saves 104 | React from having to have costly interactions with the real one, only 105 | updating it when it absolutely needs to. 106 | 107 | When rendering, React creates a tree of React elements. When state or 108 | props update, React then renders a tree of potentially different 109 | elements. The diffing algorithm figures out how to efficiently update 110 | the DOM, removing old DOM nodes and replacing them only when necessary. 111 | We give unique HTML elements unique IDs so the diffing algorithm can 112 | tell them apart. 113 | 114 | This algorithm solves the problem of generating the fewest number of 115 | operations needed to manage re-rendering. The React diffing algorithm 116 | manages to run in O(n) time (where n is the number of HTML elements) 117 | using a series of rules to determine when a node will need to be 118 | updated. 119 | -------------------------------------------------------------------------------- /schedule/questions/w4/w4a.md: -------------------------------------------------------------------------------- 1 | # Week 4 2 | 3 | ## Student A 4 | 5 | Below are the two questions that you will be asking student B. 6 | 7 | ### Routes 8 | 9 | #### Prompt 10 | 11 | What code would you have to write to generate the following routes? 12 | Also, which controller actions will each route be matched to by default? 13 | 14 | ``` 15 | GET /cats 16 | GET /cats/:id 17 | GET /cats/new 18 | POST /cats 19 | GET /cats/:id/edit 20 | PATCH /cats/:id 21 | PUT /cats/:id 22 | DELETE /cats/:id 23 | GET /cats/:cat_id/tricks 24 | POST /cats/:cat_id/tricks 25 | DELETE /cats/:cat_id/tricks/:id 26 | POST /cats/:cat_id/upvote 27 | DELETE /cats/:cat_id/upvote 28 | ``` 29 | 30 | The interviewee can reference these routes [here][routes]. 31 | 32 | [routes]: ../../code-excerpts/routes.md 33 | 34 | #### Solution 35 | 36 | This is the simplest way: 37 | 38 | ```ruby 39 | Rails.application.routes.draw do 40 | resources :cats do 41 | resources :tricks, only: [:index, :create, :destroy] 42 | resource :upvote, only: [:create, :destroy] 43 | end 44 | end 45 | ``` 46 | 47 | If the interviewee uses the above code for their routes, they will be 48 | mapped to the following controller actions. 49 | 50 | ``` 51 | GET /cats cats#index 52 | GET /cats/:id cats#show 53 | GET /cats/new cats#new 54 | POST /cats cats#create 55 | GET /cats/:id/edit cats#edit 56 | PATCH /cats/:id cats#update 57 | PUT /cats/:id cats#update 58 | DELETE /cats/:id cats#destroy 59 | GET /cats/:cat_id/tricks tricks#index 60 | POST /cats/:cat_id/tricks tricks#create 61 | DELETE /cats/:cat_id/tricks/:id tricks#destroy 62 | POST /cats/:cat_id/upvote upvotes#create 63 | DELETE /cats/:cat_id/upvote upvotes#destroy 64 | ``` 65 | 66 | ### Bad Code 67 | 68 | #### Prompt 69 | 70 | What is wrong with the following controller action, and how would you 71 | improve it? 72 | 73 | ``` ruby 74 | class CommentsController < ApplicationController 75 | def users_comments 76 | posts = Post.all 77 | comments = posts.map(&:comments).flatten 78 | @user_comments = comments.select do |comment| 79 | comment.author.username == params[:username] 80 | end 81 | end 82 | end 83 | ``` 84 | 85 | The interviewee can see the code [here][bad-code]. 86 | 87 | [bad-code]: ../../code-excerpts/bad-code.md 88 | 89 | #### Solution 90 | 91 | There are a few problems here. 92 | 93 | First and foremost is the N + 1 query. First we are fetching all posts, 94 | then we are running the `comments` method on each post, which, in turn, 95 | runs an additional query. So, for each post, we are running a query. 96 | 97 | To fix that problem, we should `includes` the comments to keep them in 98 | memory. 99 | 100 | ``` ruby 101 | posts = Post.includes(:comments).all 102 | ``` 103 | 104 | Additionally, for each comment, we are calling the `author` method, 105 | which performs an additional look up! We should all `includes` that: 106 | 107 | ``` ruby 108 | posts = Post.includes(comments: [:author]).all 109 | ``` 110 | 111 | Fixing the N + 1 query is great, but there's another general problem 112 | with this. Why are we handling the logic of the query in Ruby? There are 113 | essentially three requests that occur: one for the posts, and two to 114 | include the comments and authors in memory. This looks like something 115 | that could be delegated to SQL pretty easily with ActiveRecord. 116 | 117 | Here's an answer that returns what we're looking for in one query: 118 | 119 | ``` ruby 120 | class CommentsController < ApplicationController 121 | def users_comments 122 | username = params[:username] 123 | @user_comments = Comment.joins(:author) 124 | .where({ author: { username: username }}) 125 | end 126 | end 127 | ``` 128 | -------------------------------------------------------------------------------- /schedule/questions/w4/w4b.md: -------------------------------------------------------------------------------- 1 | # Week 4 2 | 3 | ## Student B 4 | 5 | Below are the two questions that you will be asking student A. 6 | 7 | ### Internal Project 8 | 9 | #### Prompt 10 | 11 | Our company needs an internal web application where employees can be 12 | associated with multiple projects and projects can be associated with 13 | multiple employees. How would you design the schema and models for this 14 | application? 15 | 16 | Include your database and model validations. What validations should you 17 | include? 18 | 19 | (Feel free to use `User` for the employee model and `users` for the 20 | employees table in the database.) 21 | 22 | #### Solution 23 | 24 | The key here is that users have a one-to-many relationship with projects 25 | and projects have a one-to-many relationship with users. This should 26 | signal to the interviewee that a join table will be needed. There are 27 | several names that could be used for this join table. 28 | 29 | For the validations, the interviewee ideally will think to prevent a 30 | case where a single user has multiple records for the same project. A 31 | user should only be able to be assigned to a project once. For this, 32 | they will need to validate for uniqueness on the combination of the 33 | `user_id` and `project_id`. 34 | 35 | Assuming that we choose to name the join table "assignments", the schema 36 | could look as follows. Note that they would not necessarily need to use 37 | the same `schema.rb` format. 38 | 39 | ``` ruby 40 | create_table "users", force: true do |t| 41 | t.string "name", null: false 42 | # ... Other Info ... 43 | t.datetime "created_at" 44 | t.datetime "updated_at" 45 | end 46 | 47 | 48 | create_table "assignments", force: true do |t| 49 | t.integer "user_id", null: false 50 | t.integer "project_id", null: false 51 | t.datetime "created_at" 52 | t.datetime "updated_at" 53 | end 54 | 55 | add_index "assignments", ["user_id"], name: "index_assignments_on_user_id" 56 | add_index "assignments", ["project_id"], name: "index_assignments_on_project_id" 57 | add_index "assignments", ["user_id", "project_id"], name: "index_assignments_on_user_id_and_project_id", unique: true 58 | 59 | create_table "projects", force: true do |t| 60 | t.string "name", null: false 61 | # ... Other Info ... 62 | t.datetime "created_at" 63 | t.datetime "updated_at" 64 | end 65 | ``` 66 | 67 | The models could look as follows: 68 | 69 | ``` ruby 70 | class User < ActiveRecord::Base 71 | validates :name, presence: true 72 | 73 | has_many :assignments, 74 | primary_key: :id, 75 | foreign_key: :user_id, 76 | class_name: :Assignment 77 | 78 | has_many :assigned_projects, 79 | through: :assignments, 80 | source: :project 81 | end 82 | 83 | class Assignment < ActiveRecord::Base 84 | validates :user, uniqueness: { scope: :project } 85 | 86 | belongs_to :user, 87 | primary_key: :id, 88 | foreign_key: :user_id, 89 | class_name: :User 90 | 91 | belongs_to :project, 92 | primary_key: :id, 93 | foreign_key: :project_id, 94 | class_name: :Project 95 | end 96 | 97 | class Project < ActiveRecord::Base 98 | validates :name, presence: true 99 | 100 | has_many :assignments, 101 | primary_key: :id, 102 | foreign_key: :project_id, 103 | class_name: :Assignment 104 | 105 | has_many :assignees, 106 | through: :assignments, 107 | source: :user 108 | end 109 | ``` 110 | 111 | ### CSS Pre-Processors 112 | 113 | #### Prompt 114 | 115 | Describe the advantages of using a CSS pre-processor and name some common examples. 116 | 117 | #### Solution 118 | 119 | A complete description should touch on at least three of the following: 120 | 121 | * Assign and reference variables 122 | * Iterative loops and conditional statements 123 | * Nested selectors 124 | * Custom function declaration (through `@mixin`) 125 | * Decomposition of code (through `@import` and partials) 126 | * Inheritance (through `@extend`) 127 | 128 | Examples: 129 | * Sass 130 | * SCSS 131 | * Less 132 | * Stylus 133 | -------------------------------------------------------------------------------- /schedule/questions/w3/w3b.md: -------------------------------------------------------------------------------- 1 | # Week 3 2 | 3 | ## Student B 4 | 5 | Below are the two questions that you will be asking student A. 6 | 7 | ### Caesar Cipher 8 | 9 | #### Prompt 10 | 11 | Write a function that takes a message and an increment amount and 12 | outputs the same letters shifted by that amount in the alphabet. Assume 13 | lowercase and no punctuation. Preserve spaces. 14 | 15 | #### Solution 16 | 17 | The most time-efficient way to approach this problem is to create a 18 | dictionary of letters using a structure that makes it easy and fast to 19 | access a letter at any position in the alphabet. An array will do this 20 | for us -- arrays allow us to access a value at any index in constant 21 | time. 22 | 23 | ```ruby 24 | def caesar_cipher(str, shift) 25 | letters = ("a".."z").to_a 26 | 27 | encoded_str = "" 28 | str.each_char do |char| 29 | if char == " " 30 | encoded_str << " " 31 | next 32 | end 33 | 34 | old_idx = letters.find_index(char) 35 | new_idx = (old_idx + shift) % letters.count 36 | 37 | encoded_str << letters[new_idx] 38 | end 39 | 40 | encoded_str 41 | end 42 | ``` 43 | 44 | ### OOP – Parking Lot 45 | 46 | #### Prompt 47 | 48 | Design a parking lot using object-oriented principles. 49 | 50 | (Don't spend too much time fleshing out actual methods. Aim to give a 51 | holistic view of which methods exist on each of the classes.) 52 | 53 | #### Solution 54 | 55 | This question is very open-ended. The interviewee should ask questions 56 | to specify what the design expectations are. 57 | 58 | Ensure that the interviewee aims to satisfy the following: 59 | 60 | * Each parking lot can have many floors. 61 | * Each parking lot allows for various kinds of vehicles to park. Assume 62 | these are motorcycle, car, and bus. Each of these has a different size. 63 | * There are multiple parking spot sizes. Assume those sizes are compact 64 | and regular. 65 | * The rules for parking a vehicle in a spot are something like this: 66 | * Motorcycles can take any parking spot, whether regular or compact. 67 | (They require, say, four feet of parking space.) 68 | * Cars can take any regular spot. (They require, say, an eight foot 69 | wide spot.) 70 | * Buses require, say, forty feet of parking space, so they will have 71 | to take multiple spaces. 72 | 73 | Obviously, there are many other possible questions about the structure, 74 | but the interviewee can assume that anything beyond these specifics are 75 | left to their discretion. 76 | 77 | What follows below would be a skeleton for a valid approach: 78 | 79 | ```ruby 80 | class Vehicle 81 | attr_reader :spots_needed, :size 82 | 83 | def initialize(license_plate) 84 | @parking_spots = [] 85 | @license_plate = license_plate 86 | end 87 | 88 | def park_in_spot(spot) 89 | # ... 90 | end 91 | 92 | def clear_spots 93 | # ... 94 | end 95 | 96 | def can_fit_in_spot(spot) 97 | # ... 98 | end 99 | end 100 | 101 | class Bus < Vehicle 102 | def initialize 103 | super 104 | @spots_needed = 5 105 | @size = :large 106 | end 107 | 108 | def can_fit_in_spot(spot) 109 | # Checks if spot is :large 110 | end 111 | end 112 | 113 | class Car < Vehicle 114 | def initialize 115 | super 116 | @spots_needed = 1 117 | @size = :compact 118 | end 119 | 120 | def can_fit_in_spot(spot) 121 | # Check if spot is :compact or :large 122 | end 123 | end 124 | 125 | class Motorcycle < Vehicle 126 | def initialize 127 | super 128 | @spots_needed = 1 129 | @size = :compact 130 | end 131 | end 132 | 133 | class ParkingLot 134 | def initialize 135 | @levels = # generate_levels 136 | end 137 | 138 | def park_vehicle(vehicle) 139 | # Park the vehicle in a spot or multiple spots. Return false if failed. 140 | end 141 | end 142 | 143 | class Level 144 | def initialize(floor, num_spots) 145 | @spots = # generate spots 146 | @available_spots = num_spots 147 | @floor = floor 148 | end 149 | 150 | def park_vehicle(vehicle) 151 | # Find a place to park vehicle or return false. 152 | end 153 | 154 | def park_starting_at(spot_num, vehicle) 155 | # Park a vehicle starting at spot number and continue until vehicle.spots_needed. 156 | end 157 | 158 | def find_available_spots(vehicle) 159 | # Find a spot to park the vehicle. Return index of spot or -1. 160 | end 161 | 162 | def spot_freed 163 | @available_spots += 1 164 | end 165 | end 166 | 167 | class ParkingSpot 168 | attr_reader :row, :spot_num 169 | 170 | def initialize(size, level, row, spot_num) 171 | @vehicle = nil 172 | @spot_size = size 173 | @level = level 174 | @row = row 175 | @spot_num = spot_num 176 | end 177 | 178 | def is_free? 179 | !@vehicle 180 | end 181 | 182 | def can_fit_vehicle?(vehicle) 183 | # Check it will fit. 184 | end 185 | 186 | def park(vehicle) 187 | # Park in spot 188 | end 189 | 190 | def unpark 191 | # Remove vehicle from spot and notify level that a new spot is available. 192 | end 193 | end 194 | ``` 195 | -------------------------------------------------------------------------------- /schedule/questions/w7/w7a.md: -------------------------------------------------------------------------------- 1 | # Week 7 2 | 3 | ## Student A 4 | 5 | Below are the two questions that you will be asking student B. 6 | 7 | ### Bad Code 8 | 9 | #### Prompt 10 | 11 | A junior software engineer at our company wrote the following code. 12 | There are at least six problems with it. What are those problems, and 13 | how would you fix them? Also, what does the component do? And can you 14 | give an example of how it could be used? 15 | 16 | Feel free to let the interviewee view the code 17 | [here][geiger-code-excerpt]. 18 | 19 | ```js 20 | import React from 'react'; 21 | 22 | class GeigerCounter extends React.Component { 23 | constructor() { 24 | this.state = { 25 | counts: [false], 26 | probability: 50, 27 | maxCountsSize: this.props.maxCountsSize || 30, 28 | }; 29 | } 30 | 31 | componentDidMount() { 32 | this.startCounter(); 33 | } 34 | 35 | startCounter() { 36 | setInterval(() => { 37 | this.updateCounts(); 38 | }, 1000); 39 | } 40 | 41 | updateCounts() { 42 | const booleanVal = this.generateBoolean(); 43 | 44 | const newCounts; 45 | 46 | if (this.state.counts.length < this.state.maxCountsSize) { 47 | newCounts = this.state.counts.concat([booleanVal]); 48 | } else { 49 | newCounts = this.state.counts.slice(1).concat([booleanVal]); 50 | } 51 | 52 | this.setState({ counts: newCounts }); 53 | console.log(this.state.counts.length); 54 | } 55 | 56 | generateBoolean() { 57 | const floatProbability = this.state.probability / 100.0; 58 | const randFloat = Math.random(); 59 | 60 | return randFloat < floatProbability; 61 | } 62 | 63 | geigerValue() { 64 | const { length } = this.state.counts; 65 | 66 | const trueCounts = 0; 67 | 68 | for (let i = 0; i < length; i++) { 69 | if (this.state.counts[i]) trueCounts++; 70 | } 71 | 72 | return trueCounts / length; 73 | } 74 | 75 | updateProbability(value) { 76 | const newValue = this.state.probability + value; 77 | if (newValue >= 0 && newValue <= 100) { 78 | this.setState({ probability: newValue }); 79 | } 80 | } 81 | 82 | render() { 83 | return ( 84 |
85 |

86 | The radiation level is currently: {this.geigerValue()} 87 |

88 | 89 | The current radiation level is at {this.state.probability}% 90 | 91 | 92 |
93 | 94 | 95 | 96 |
97 | ); 98 | } 99 | } 100 | ``` 101 | 102 | [geiger-code-excerpt]: ../../code-excerpts/geiger-counter.md 103 | 104 | #### Solution 105 | 106 | It can be tricky to find errors in code without running it. If the 107 | interviewee is having trouble finding the following problems, try to 108 | nudge them in the right direction. 109 | 110 | ##### The Errors 111 | 112 | ###### Missing `super` 113 | 114 | In the constructor, there should be a call of `super(props);` at the 115 | beginning. There should also be `props` passes in to the constructor. 116 | 117 | ###### Inappropriate `const` 118 | 119 | In the `updateCounts` function, we are using `const newCounts;`, but 120 | it's conditionally assigned a value in the lines that follow that 121 | declaration. Use `let` instead! 122 | 123 | ###### Infinite Interval 124 | 125 | This one can be hard to spot. The `startCounter` method called in the 126 | `componentDidMount` starts a `setInterval`, but when a component is 127 | unmounted, the interval will remain. To fix this, you would want to 128 | assign the interval so that it could be referenced and cleared later: 129 | 130 | ```js 131 | startCounter() { 132 | this.interval = setInterval(() => {...}, 1000); 133 | } 134 | 135 | componentWillUnmount() { 136 | clearInterval(this.interval); 137 | } 138 | ``` 139 | 140 | ###### Async State Update 141 | 142 | Inside `updateCounts`, we have a console log that depends on the state 143 | after the `this.setState(...)`. Because `setState` is asynchronous, it 144 | may or may not return the correct value. Instead, we should pass it as a 145 | callback like so: 146 | 147 | ```js 148 | this.setState({...}, () => console.log(...)); 149 | ``` 150 | 151 | ###### Click Callback 152 | 153 | Each `onClick` should be a callback, not an invoked function. We should 154 | have something like this `onClick={() => this.updateProbability(1)}`. 155 | 156 | Alternatively, you could rework the `updateProbability` function to 157 | return a function. In that case, you would want to bind 158 | `updateProbability` so that `this` is the appropriate context. 159 | 160 | ###### Missing Bind 161 | 162 | Because we are directly invoking `this.geigerValue` in the render 163 | function, we should make sure it is properly bound. Add the following 164 | to your constructor: 165 | 166 | ```js 167 | this.geigerValue = this.geigerValue.bind(this); 168 | ``` 169 | 170 | ##### Usage 171 | 172 | This component could be used like this: 173 | 174 | ```js 175 | 176 | ``` 177 | 178 | ### React – Contrast and Compare 179 | 180 | #### Prompt 181 | 182 | Other front-end frameworks and libraries exist. What are some examples 183 | of these, and how does React compare/contrast with those? 184 | 185 | #### Solution 186 | 187 | ##### jQuery 188 | 189 | Like React, jQuery is a library, not a framework. It is the most popular 190 | JavaScript library in use. It wraps up many common vanilla JavaScript 191 | functions and initially gained popularity because it is guaranteed to 192 | behave identically on any browser. 193 | 194 | A key contrast: the components rendered by React are a pure function of 195 | the React state, i.e. props and component state. Thus a React developer 196 | only has to think about the state of his app. On the other hand, jQuery 197 | primarily allows you to directly manipulate the DOM, meaning that it is 198 | up to the programer to keep the DOM in sync with the internal state of 199 | an app. 200 | 201 | ##### Vue 202 | 203 | Vue is another front-end library. Like react it uses a virtual DOM and 204 | composable components. Vue's virtual DOM is lighter weight than React, 205 | and Vue is significantly faster, however Vue's developer community is 206 | much smaller than React's, so Vue has a smaller ecosystem of libraries 207 | and plugins. 208 | 209 | ##### Angular 210 | 211 | Angular was initially released in 2009 and is maintained by Google and a 212 | community of developers. It is part of the MEAN stack: the MongoDB 213 | database, Express.js server, Angular.js, and Node.js. 214 | 215 | Angular is a framework, not a library like React, and implements a MVVM 216 | framework (Model-View-ViewModel). As a result, it offers perhaps more 217 | functionality out of the box than React. However, it also takes much 218 | more time to master and is criticized in some corners for its lack of 219 | flexibility. Angular 1.0 also struggled to handle larger amounts of 220 | data. With the release of Angular 2.0, its ability to render large 221 | amounts of data in the browser has increased. However, it still loses 222 | out to React in terms of performance. 223 | 224 | ##### Ember 225 | 226 | Like Angular, Ember is a framework and not just a library. It has a 227 | number of customizations that can be added to the app from the Ember CLI 228 | (an idea the Ember team took from Rails!), as well as built in testing 229 | tools. However, it doesn't have a particularly large core team so 230 | development is slow. The community, while vibrant, doesn't produce as 231 | many add-ons. Also, because Ember is a framework, it's harder to 232 | customize. 233 | 234 | ##### React Native 235 | 236 | React Native allows developers to write React apps in javascript and run 237 | them on mobile devices. It was released by Facebook and is also used by 238 | companies like AirBnB and Instagram. It is currently supported by iOS 239 | and Android. Microsoft also has plans to start supporting React Native 240 | apps on Windows devices. 241 | --------------------------------------------------------------------------------