diff --git a/README.md b/README.md index f9fef98..d5c17a7 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# concepts \ No newline at end of file +# concepts + +> This repository has been deprecated. + +Formerly it served as the location for concepts in the student handbook, which was a separate repository. We found there wasn't any value in separating the content from the book so the concepts have been moved into the [student handbook](https://github.com/dev-academy-programme/book-source). Only the concepts being used at the time were migrated out of this repo. diff --git a/agile/introduction.md b/agile/introduction.md index a0c543f..b89dee0 100644 --- a/agile/introduction.md +++ b/agile/introduction.md @@ -1,7 +1,8 @@ -Agile is a methodology for software development whose aims include responsiveness, flexibility, and early/continuous delivery of products. +# Agile Software Development +Agile is a methodology for software development whose aims include responsiveness, flexibility, and early/continuous delivery of products. -### Why? +## Why? Agile's origins date back to the 1970s. People started becoming frustrated with the traditional 'waterfall' model of development: @@ -22,17 +23,17 @@ Trouble is, often what the finished product actually needs to be can't be determ > At the end of a project, a team might have built the software it was asked to build, but, in the time it took to create, business realities have changed so dramatically that the product is irrelevant. In that scenario, a company has spent time and money to create software that no one wants. Couldn’t it have been possible to ensure the end product would still be relevant before it was actually finished? ~ [agilemethodology.org](https://agilemethodology.org) -### Scrum +## Scrum Scrum is the most common/popular approach to Agile development. You can read more about it on Wikipedia. Some people use the terms interchangeably, but strictly speaking Scrum is _a kind_ of Agile. Another way to describe it: Scrum is a _framework_ for Agile development. It gives specific guidance on roles (Product Owner, Scrum Master) and the process or order of events. Most of the following content is related to "Scrum-flavoured Agile". -### Team composition +## Team composition Traditional teams are often siloed: all the management/architects together, all the designers together, all the developers together, all the testers together. Agile development encourages teams to be _cross-functional_: made up of people from many different disciplines. Scrum encourages self-organising teams. -### Iteration +## Iteration In Agile, we try to incorporate a little of each phase of development (requirements, design, develop, etc) into short cycles, often called _sprints_. The idea is to have code that could potentially be _shipped_ (deployed, published) at the end of each sprint. Two week sprints are common. @@ -40,19 +41,19 @@ In Agile, we try to incorporate a little of each phase of development (requireme [Source](https://commons.wikimedia.org/wiki/File:Agile_Project_Management_by_Planbox.png) -### The backlog +## The backlog A backlog is a list of tasks that together make up an application: if you completed all of them, you'd have a great product! Some are product features, but not all: documentation and bug fixes are also entered on the backlog. Items on the backlog may be further classified with labels: is it a feature or a bug? Is it considered part of the Minimum Viable Product? Is it frontend or backend, or both? The backlog is likely to feature _user stories_, and may break each story into multiple tasks to be completed. -### Sprint planning +## Sprint planning At the start of each sprint, a [meeting](http://www.leadingagile.com/2012/08/simple-cheat-sheet-to-sprint-planning-meeting/) is held to set the scope of the sprint, deciding which tasks will be completed by the end of it. -### Stand-up +## Stand-up Held daily, the stand-up (or "scrum") should be carefully timeboxed and starts even with missing team members. Everybody should report: @@ -63,19 +64,19 @@ Held daily, the stand-up (or "scrum") should be carefully timeboxed and starts e This isn't the time for long discussions! Standups are for quick summaries. For most teams they shouldn't take longer than 15 minutes. A scrum master or similar role will keep track of blocks that might affect the ability of the team to deliver on time, and who on the team is assigned to resolve the block. -### Sprint review +## Sprint review Review the work that was completed, and what was not completed. Demo the working code. Don't demo what was not completed! -### Sprint retrospective +## Sprint retrospective What went well? What could we do differently or better next time? This is a great chance to learn from the previous weeks. It should not be used as an opportunity to cast _blame_, however. Instead, identify _systemic_ problems. How could our team improve to overcome the difficulties we experienced? -### Resources +## Resources - http://agilemethodology.org/ - http://scrumreferencecard.com/ diff --git a/agile/user-stories.md b/agile/user-stories.md deleted file mode 100644 index 3bf88f3..0000000 --- a/agile/user-stories.md +++ /dev/null @@ -1,20 +0,0 @@ -One way to represent a feature you'd like your program to have is the [user story](https://manifesto.co.uk/agile-concepts-user-stories/). This is a formulaic description of a 'want' that the user has. - - -### Format - -User stories follow a distinct format: - -> As a _[ persona ]_ I want _[ feature ]_ so that I can _[ justification ]_. - -Some examples: - - * As a user I want to login with username and password so that I can access my information. - * As a user I want to login with Facebook so that I don't have to remember another password. - * As a user I want to change my profile picture because I don't look like that anymore. - * As an administrator I can view a list of users so that I can manage my site. - - -### Why? - -User stories divide our programs into discrete 'chunks' that can easily be worked on separately. They help us understand and manage the _scope_ and priority of our work: which features we should add next, and which are _must have_ as opposed to _nice to have_. They also help us keep the end user in mind: you know, that person we're actually developing all this for! diff --git a/ajax/ajax-intro.md b/ajax/ajax-intro.md deleted file mode 100644 index 0bb836d..0000000 --- a/ajax/ajax-intro.md +++ /dev/null @@ -1,3 +0,0 @@ -In the browser these are often called AJAX, or XHR. - -It's easy to issue HTTP requests to other sites, but if the site the page came from doesn't have the same domain name as the site you're calling, you'll hit the limitations of [Cross-origin Request Sharing (CORS0](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) unless you're making requests to an API that explicitly allows it. diff --git a/ajax/cors.md b/ajax/cors.md deleted file mode 100644 index 6d14b97..0000000 --- a/ajax/cors.md +++ /dev/null @@ -1,9 +0,0 @@ -A resource makes a cross-origin HTTP request when it requests a different type of resource from a different domain. For example, an HTML page served from http://accio.com makes an src request for http://lumos.com/light.jpg. Many pages on the web today load resources like CSS stylesheets, images and scripts from separate domains; such as the [jQuery](https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-rc1/jquery.js) or [normalise](https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.css) CDN. - -For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. So, a web application using XMLHttpRequest could only make HTTP requests to its own domain. - -To get around this, on both the server and the request we have to explicitly state what type of requests and data we expect. CORS is a way to work safely within Cross Origin Resouce Sharing. CORS gives web servers cross-domain access controls, which enable secure cross-domain data transfers. Modern browsers use CORS in an API container - such as XMLHttpRequest - to mitigate risks of cross-origin HTTP requests. - -There are some good examples of this in action on the W3 page [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) or another one [here](http://www.html5rocks.com/en/tutorials/cors/) - -Within the wonderful world of express.js, we can set what content we expect in our servers using this fabulous and easy to use module, [npm cors](https://www.npmjs.com/package/cors) (other modules are available!) diff --git a/api/api-proxy.jpg b/api/api-proxy.jpg deleted file mode 100644 index fccefbc..0000000 Binary files a/api/api-proxy.jpg and /dev/null differ diff --git a/api/cors.md b/api/cors.md deleted file mode 100644 index 2d1b2cb..0000000 --- a/api/cors.md +++ /dev/null @@ -1,21 +0,0 @@ -Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another origin outside the domain from which the first resource was served. For example, if our web app hosted at https://blog.foo.com and in our `index.html` page we have ``, that image (a resource) is considered be shared cross-origin. Some resources are not considered _restricted_. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos. Certain "cross-origin" requests, notably Ajax requests (web API calls), however are forbidden by default by the [same-origin security policy](https://en.wikipedia.org/wiki/Same-origin_policy). The same-origin security policy is a feature of web browsers that prevent a web page from one origin to run scripts from a different origin. - - -### What defines an origin? - -The origin of a resource is defined by its URL. Specifically, the part of the URL before the first folder or file. Here are some examples of cross-origin and same-origin URLs: - -* http://foo.com and https://foo.com: **cross-origin** because of different [URI schemes](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) (http/https) -* http://www.foo.com and http://blog.foo.com: **cross-origin** because of different [hostnames](https://en.wikipedia.org/wiki/Hostname) (www/blog) -* http://foo.com:3000 and http://foo.com:8080: **cross-origin** because of different [ports](https://en.wikipedia.org/wiki/Port_(computer_networking)) (3000/8080) -* http://foo.com and http://bar.com: **cross-origin** because of different domain names (foo/bar) -* http://foo.com/profile and http://foo.com/v1/users: **same-origin** - - -### Configuring CORS - -CORS can only be configured on the server that provides the restricted resource. That means if we want to consume an API from the browser, and the URL of the API doesn't have the same origin as the page our script is running in, the server must be configured to allow requests from other origins. When a web API server has been configured to accept requests from other origins, it will include an `Access-Control-Allow-Origin` HTTP response header. As long as our client-side script came from a matching origin, we shouldn't be effected by the same-origin security policy. - -But what if we can't change the configuration on the server? That just means we can't consume the API from a web browser. That doesn't mean we can't consume the API from our server. We can route requests from our client via our server (we won't need a CORS setup if our client and server have the same origin) and get our server to hit other servers. Note that our server doesn't have same-origin constraint, because the primary reason for a same-origin constraint is to avoid scripts running within a browser to read or interfere with the browser's DOM. This illustrates the relationship and calling pattern of the client getting results from the external API via our server. - -![proxying an api call](./api-proxy.jpg) diff --git a/api/crud-rest.md b/api/crud-rest.md deleted file mode 100644 index 49ee411..0000000 --- a/api/crud-rest.md +++ /dev/null @@ -1,30 +0,0 @@ - Resource action | Associated HTTP request -:----------------|:------------------------ - **C**reate | `POST` - **R**ead | `GET` - **U**pdate | `PUT` - **D**estroy | `DELETE` - -REST = Representational State Transfer - - -### Example: managing users - -CRUD is a way of talking about the basic actions we might want to perform with users: - - create a new user - - see all the users - - see a particular user - - update a particular user - - delete a particular user - - - Resource action | Path/route | HTTP request | ? -:----------------|:-----------|:-------------|------ - **C**reate | `/users` | `POST` | creates a new user with the parcel of data you have `POST`ed - **R**ead | `/users` | `GET` | `GET` a list of all users - **R**ead | `/users/5` | `GET` | `GET` the data of user 5 - **U**pdate | `/users/5` | `PUT` | update the date of user 5 with data you have `PUT` - **D**estroy | `/users/5` | `DELETE` | `DELETE` / destroy user 5 - | `/users/new`| `GET` | `GET` the form for creating a new user - | `/users/5/edit` | `GET` | `GET` the form for editing a new user - diff --git a/api/intro.md b/api/intro.md index 27eed92..611fdc8 100644 --- a/api/intro.md +++ b/api/intro.md @@ -1,4 +1,6 @@ -Application Programming Interface - not an initialism that feels particularly useful. +# Application Programming Interface + +Admittedly not an initialism that feels particularly useful. Essentially, an API is a point where you can access information if you ask for it in a specific manner. @@ -15,3 +17,4 @@ If we ask the bank teller through the window (*endpoint*) 'Hey, can I have $300? Imagine if you will, you go to the bank window (*endpoint*) wearing a mask, waving a toy gun around and shouting 'GIVE ME ALL THE MONEY!' You are not going to get any money (if the bank's security is sufficiently strong!) This highlights one of the most important features of using an API: there will be a specific way in which you can interact with them, which will be listed in its documentation. If you don't ask an API for information in a way it expects, you will not get your required data. + diff --git a/api/keys.md b/api/keys.md deleted file mode 100644 index 440a5ae..0000000 --- a/api/keys.md +++ /dev/null @@ -1,15 +0,0 @@ -It isn't uncommon when consuming an external web API that you'll need to authenticate your app in order to use it. Often this authentication doesn't need a high security solution; for example when accessing non-sensative read-only data. In these cases, we only need to send a string that identifies our app. We call this string a _key_. We usually get this key from the admin section of our developer user account on the site. In the case of [mashape.com](https://mashape.com), we must send this key as the value of a `X-Mashape-Authorization` HTTP request header in each of our API calls. - -When using [`superagent`](https://github.com/visionmedia/superagent), we might make the request like this: - -```js -request - .get('https://numbersapi.p.mashape.com/1/22/date') - .set('X-Mashape-Authorization', '7zdlxkb3jqmshIgOJzR0qN5NdQc3p1PxmhXjsnJvX4hNVr2Yio') - .set('Accept', 'application/json') - .end(function(err, res){ - console.log(res.body.text) - }) -``` - -This does require you to send your API key to the browser, which yes, means anyone can see your key and potentially use it. It also means you're probably commiting the key to your source control repository. In low security scenarios this can be okay. We will explore more secure scenarios later in the bootcamp, but what if you don't want to include your key in the client-side code even in low security scenarios? In this case you will need to consume the API from a server, your own API. Doing so will keep the key out of source control and away from any browsers. If you take this approach, consider using [`dotenv`](https://www.npmjs.com/package/dotenv) as a place to keep your API key. You'll place the key in a `.env` file and make sure this file has an entry in your `.gitignore` file. The npm package is smart enough to use the contents of the `.env` file when it can find it, and use normal environment variables when it can't... diff --git a/api/supertest.md b/api/supertest.md deleted file mode 100644 index d93ad04..0000000 --- a/api/supertest.md +++ /dev/null @@ -1,36 +0,0 @@ -[Supertest](https://www.npmjs.com/package/supertest) is a great way to test APIs. The way you use it is quite similar to [Superagent](https://www.npmjs.com/package/superagent). - -Here's some example usage, which incorporates tape. - -```js -var request = require('supertest') -var test = require('tape') - -var app = require('../app.js') - -test('/users route returns an object containing an array of users', function (t) { - // Arrange - var expected = true - - // Act - request(app) - .get('/users') - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - // Assert - t.equal(err, null) - t.equal(Array.isArray(res.body.users), expected) - t.end() - }) -}) - -// Close any open connections -test.onFinish(function () { - process.exit(0) -}) -``` - -Here Supertest is using its API testing tools (`expect`) to check the headers and HTTP status code it receives from its GET request to `/users`. It gives us the response to test in `.end()`. The test checks several things: first, that no error was returned; second, that there is a property named `users` on the response body, and that it is an array. - -We can't test the exact content being returned from the route because it could be different each time. We'd have to have the exact same database records every time we ran the test to ensure predictable behaviour. Tests that examine a route in this way are often referred to as _integration tests_, because they use multiple parts of the system (the database, network and filesystem in particular) which are not [mocked](https://en.wikipedia.org/wiki/Mock_object#Use_in_test-driven_development). diff --git a/api/versioning.md b/api/versioning.md index 6c6431d..1d576dd 100644 --- a/api/versioning.md +++ b/api/versioning.md @@ -1,7 +1,6 @@ -APIs should be properly versioned. -APIs evolve and change, we must do this while supporting old versions. -Otherwise, if you just change your API, a lot of your clients would be in trouble. -Although, we won't be developing multiple versions (today we're working on V1), it is important that we plan for the future and properly namespace our documentation and work under V1 namespace. +# Versioning APIs + +APIs should be properly versioned. APIs evolve and change, we must do this while supporting old versions. Otherwise, if you just change your API, a lot of your clients would be in trouble. Although, we won't be developing multiple versions (today we're working on V1), it is important that we plan for the future and properly namespace our documentation and work under V1 namespace. Here's our v2 api: get a list of all cats at `/cats` @@ -15,4 +14,5 @@ The original route for getting all the cats was `/show_me_the_cats` ``` api/v1/show_me_the_cats -``` \ No newline at end of file +``` + diff --git a/api/web-apis.md b/api/web-apis.md deleted file mode 100644 index 2ebf0e4..0000000 --- a/api/web-apis.md +++ /dev/null @@ -1,49 +0,0 @@ -Web APIs are interfaces for other applications instead of users. They don't have a visual interface - only data. We often refer to these blocks of data returned from web APIs as _resources_. A resource maps very closely to what you understand as a database entity/table, a type of thing you are storing. - - -## REST and JSON - -REST stands for Representational State Transfer and was coined by Roy Fielding in his PhD dissertation titled [Architectural Styles and the design of Network-based Software Architectures](https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm). Chapter 5 describes stateless entities (what we're storing in our database) as resources. It also describes how we can refer to these resources using a uniform indicator: the URL. This is why you will see URLs describe individual resources like this: `/widgets/213/characteristics`. - -JSON, JavaScript Object Notation, is a string representation for JavaScript objects. We can use `JSON.stringify(jsObj)` to convert (serialise) a JavaScript object to a string, and `JSON.parse(jsonString)` to convert (deserialise) a JSON string back to a JavaScript object. Fortunately, Express.js can do this for us as we'll see below. This is the recommended (and most common) format for REST API requests and responses. - - -## Exposing web API routes - -Routes are exposed for web APIs in the same way they are for routes that return other web assets. The main difference is they accept and respond with JSON. - -There are a few different things you should notice about the code samples below. The endpoints they define use an `:id` syntax and `req.params` rather than `req.query` we've seen before. Using route params is more explicit and much more common with REST web APIs. - -### Returning JSON - -We use `res.json` to return JSON to the caller: - - ```js - // server.js - var widgets = require('./routes/widgets') - app.use('/widgets', widgets) - - // routes/widgets.js - var express = require('express') - var router = express.Router() - - router.get('/:id', function (req, res) { - var id = req.params.id - res.json({id: id, name: 'Best widget'}) - }) - - module.exports = router - ``` - -Notice how it just uses a normal JavaScript object. The `.json()` method will take care of serialising the object to JSON. - -Don't forget Express.js is also capable of receiving JSON in the request body using the `body-parser` middleware module. This is common when using the POST and PUT verbs to insert and update resources. - -```js -// server.js -var express = require('express') -var bodyParser = require('body-parser') -var app = express() -app.use(bodyParser.json()) -``` - diff --git a/architecture-patterns/mvc-intro.md b/architecture-patterns/mvc-intro.md deleted file mode 100644 index 1c41b3d..0000000 --- a/architecture-patterns/mvc-intro.md +++ /dev/null @@ -1,10 +0,0 @@ -Building database-driven web applications requires a lot of moving parts: the server, views, routes, data access code, etc. For your application to be maintainable, it's very important to adhere to the _Single Responsibility Principle_ by putting each of these responsibilities in their own modules (files). - -Model-View-Controller (MVC) is one of the most common _separated presentation_ patterns. These patterns describe how to structure code according to the Single Responsibility Principle. - -**Model** is the data representation we apply to our templates. This is the second parameter we've been passing to templates with `res.render('view', model)`. We've also called it a _view model_ because this model is built specifically for a view. - -**View** is the visual representation part of the code - our templates. We've built these using HTML and Handlebars. - -**Controller** is the code that coordinates the interaction of the data (the model) and the view. We've been doing this in our `routes.js` file, but that often causes our routes to do too much. By creating a separate `controller.js` we can reduce the responsibility of our routes to get the view model from the controller, and apply it to the view. - diff --git a/architecture-patterns/orm-intro.md b/architecture-patterns/orm-intro.md deleted file mode 100644 index 601f8b2..0000000 --- a/architecture-patterns/orm-intro.md +++ /dev/null @@ -1,3 +0,0 @@ -And object relational map a layer which helps you map data between different places. -In the context of MVC, this is from your database to a model and back. -Not all MVC frameworks have an ORM. \ No newline at end of file diff --git a/async/callback-hell.md b/async/callback-hell.md deleted file mode 100644 index 8377c4d..0000000 --- a/async/callback-hell.md +++ /dev/null @@ -1,5 +0,0 @@ -When your asynchronous function calls another asynchronous function, which calls another asynchronous function, your callbacks can get quite nested. - -This anti-pattern can make your code very difficult to read and maintain. - -It's affectionately, and appropriately, known as called "[callback hell](http://callbackhell.com/)." diff --git a/async/callbacks.md b/async/callbacks.md deleted file mode 100644 index 71e9448..0000000 --- a/async/callbacks.md +++ /dev/null @@ -1,83 +0,0 @@ -A _callback_ is a function we pass to another function as a parameter. When the receiving function wants to send something _back_ to the first function, it _calls_ the callback. - -Remember `Array.map()`? It takes a callback function as a parameter: - -```js -// Returns [2, 3, 4] -[1, 2, 3].map(function (n) { - return n + 1 -}) -``` - -The anonymous function passed to `map` is called by `map`: we don't call it ourselves, we just tell it what to do once it gets called. This is a very common pattern in functional programming. - - -## "Hello, Metaphorical Pizza?" - -We often use callbacks when working with _asynchronous functions_. An async function will go off and do its work, then call the callback you passed to it when it has some results to give you (or an error to report). In the meantime, the rest of your program continues on its merry way, not waiting for the operation to complete. - -Say you're hungry, and you order a pizza. You don't know ahead of time how long the pizza is going to take to arrive (30 min guarantees notwithstanding) and you're certainly not going to stand there doing nothing while you wait. You go on doing whatever you were doing, but you've provided your address to the pizza place so that when your order is ready, they can deliver it to you. They can also report an error: "We ran out of anchovies", or "The oven exploded". - -```js -function deliver(err, pizza) { - if (!err) { - answerTheDoor() - payFor(pizza) - enjoy(pizza) - } -} - -orderAPizza('pepperoni', deliver) -makeCoffee() -callFriends() -``` - -In this example, `deliver` is a function being used as a callback. We immediately go on to doing other things after we've called `orderAPizza`, and the code inside the callback will only execute when the pizza place calls `deliver(null, pizza)`. (See below for why we used `null` here.) - -Async functions might take a little getting used to in the beginning, but you'll use them a _lot_ in your JavaScript programming and they will become second nature. - - -## Reading from a file - -Node programs often pass callback functions that handle the data you expect to receive from APIs, from databases, or from the filesystem. The filesystem is an easily accessible way of practicing this technique. - -```js -var fs = require('fs') - -fs.readFile('animals.txt', 'utf8', function (err, animals) { - if (err) { - console.error("Couldn't read file:", err.message) - } else { - console.log(animals) - } -}) -``` - -This program reads a file from the directory in which it was run, and outputs the result to the terminal. Try it! When you're done, try modifying the string `'animals.txt'` to a filename you know _doesn't_ exist, and run the program again. You should see an error that Node can't open the file you asked for. - -The first thing to notice about this example is that everything interesting happens _inside the callback_. Remember, we're not making things happen ourselves: we're _defining_ what _will_ happen once `readFile` has finished its work: once it has either succeeded or failed to deliver the contents of the file. - -The next thing to notice is that the callback has a very particular structure. It's an _error-first callback_, a common convention in the Node world which assumes that the first parameter of the callback will always be either an error object or `null`. We should always check the error to make certain it's `null` before we try to use the `animals` parameter. - -This is a really common pattern in JavaScript programs. You'll be seeing it a lot, so get some practice in! - - -## Named callbacks - -The callback doesn't have to be an anonymous function. It's often better to use a named function, both because it can be re-used and because it can be more readable: - -```js -fs.readFile('birds.txt', 'utf8', displayFileContents) -fs.readFile('trees.txt', 'utf8', displayFileContents) - -function displayFileContents (err, contents) { - if (err) { - console.error("Couldn't read file:", err.message) - } else { - console.log(contents) - } -}) -``` - -Right away this makes our code a bit more DRY. We have to do the same thing with both files so why write the function twice? It can also make the code easier to debug since we only have to look in one location for the problem. - diff --git a/async/consuming-promises.md b/async/consuming-promises.md deleted file mode 100644 index 9774a48..0000000 --- a/async/consuming-promises.md +++ /dev/null @@ -1,80 +0,0 @@ -Promises are another approach to asynchronous programming - one which conveniently allows us to sidestep callback-hell. - -Functions which perform asynchronous operations (such as interacting with the file system or a database) can return a promise which is **then** _resolved_ later. If that promise can't be kept (something is _rejected_) we can **catch** the error and deal with it. - -## `then` and `catch` - -```js -getDataFromServer() - .then(doSomethingWithData) - .catch(handleError) -``` -This example is about as simple as it gets. We don't need to understand the exact details of how to return a promise in order to use `getDataFromServer`. We just need to expect that: - -1. The `then` function will call `doSomethingWithData` if there is no error. `doSomethingWithData` can be passed a value. -2. The `catch` function will call `handleError` if there is an error, and `handleError` will be passed an error (often a JavaScript `Error` object). - -It may be helpful to see the same code again using inline anonymous functions (though we should still try to use named functions for clarity): -```js -getDataFromServer() - .then(function (data) { - console.log(data) - }) - .catch(function (err) { - console.error(err) - }) -``` -If `getDataFromServer` returns a _resolved_ promise, `then` will be called (and `catch` won't be). If it returns a _rejected_ promise, `catch` will be called (and `then` won't be). - -If you are familiar with callbacks, you'll notice it's like a callback that has had the `err` and the `data` handling parts separated. The same thing might be written like this with callbacks: - -```js -getDataFromServer( function(err, data) { - if (err) { - console.error(err.message) - return - } - - console.log(data) -}) -``` - -## Promise chains - -We can also string together quite long 'promise chains' which define the order certain tasks should occur in: - -```js -getDataFromServer() - .then(checkTheData) - .then(displayTheData) - .then(modifyTheData) - .then(saveTheData) - .catch(handleError) -``` -So long as each function in the chain returns a data object, this will help ensure everything takes place in the correct order. For example, `modifyTheData` would not be called before `checkTheData`. - -## Knex.js - -We can see this being put to work with the Knex library when accessing a database. A simple example: inserting a row, then querying the table and displaying the results. -```js -knex.insert({ - name: 'Daisy', - age: 15 - }) - .into('dogs') - .then(getNames) - .then(showNames) - .catch(displayError) - -function getNames () { - return knex('dogs').select('dogs.name') -} - -function showNames (names) { - console.log(names) -} - -function displayError (err) { - console.error(err) -} -``` diff --git a/async/fs.md b/async/fs.md deleted file mode 100644 index dc1c9d3..0000000 --- a/async/fs.md +++ /dev/null @@ -1,60 +0,0 @@ -Reading and writing files on the filesystem (the hard drive) is a common asynchronous operation. Node.js provides both synchronous and asynchronous functions to read and write files. You can see this in the documentation for [`readFile`](https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback) (the async version) and [`readFileSync`](https://nodejs.org/api/fs.html#fs_fs_readfilesync_file_options) (the synchronous version). As you can see from the documentation for the [`fs`](https://nodejs.org/api/fs.html) module, it provides a _lot_ of functionality. - -Filesystem access is part of a broader type of operations called **IO**, which stands for Input/Output. IO also includes accessing databases and communicating on a network. We're spending most of our time using the HTTP protocol when communicating over networks, but IO includes all protocols and data formats, and databases. All IO operations should be performed asynchronously because they often take much longer than performing the in-memory tasks most of our application is written to do. - -Most of our web development work will not include operating on files. Most of it will involve databases and network communication. However, filesystem operations provide a great precursor into the asynchronous programming practices we'll apply with databases and networking, without having to understand the surrounding technology. The added benefit is understanding how to work with files, which is _very_ handy when programming local scripts. - - -### Reading a text file - -To read a text file, we need the path to the file we want to read. In the example below, we're using the `path.join` function to create the path to the `students.json` file. - -```js -// Include modules provided by Node.js -var fs = require('fs') -var path = require('path') - -function readAsync () { - var studentsFile = path.join(__dirname, 'students.json') - fs.readFile(studentsFile, 'utf-8', showContents) -} - -function showContents (err, contents) { - if (err) { - return console.log(err.message) - } - console.log(contents) -} -``` - -The contents of the file, `contents`, will be passed into our error-first callback function. We're console logging the contents if no error was provided. - - -### Writing a text file - -To write a text file, we need the path we want to create and the contents we want for the file. - -```js -// Include modules provided by Node.js -var fs = require('fs') -var path = require('path') - -function writeAsync () { - var teacherFile = path.join(__dirname, 'teacher.json') - var teacherJson = JSON.stringify({name: 'Don'}) - fs.writeFile(teacherFile, teacherJson, function (err) { - if (!err) { - verifyExists(teacherFile) - } - }) -} - -function verifyExists (teacherFile) { - fs.exists(teacherFile, function(exists) { - console.log(teacherFile, 'exists:', exists) - }) -} -``` - -Instead of having to create a string buffer, the `writeFile` function will also accept just a normal string, which is returned from `JSON.stringify`. The anonymous function we're using as our error-first callback only accepts an error because there isn't anything else to return. If no error is provided we use `fs.exists` to determine if the file was created. - diff --git a/async/promises.md b/async/promises.md index 2e5a02b..448025d 100644 --- a/async/promises.md +++ b/async/promises.md @@ -1,7 +1,6 @@ -Promises are a pattern/ style/ opinion about how to write synchronous functions. -They are a direct response to Callback Hell. +Promises are a pattern/style for writing synchronous functions. They are a direct response to Callback Hell. -Here's an example of what a promisified superagent function looks like : +Here's an example of what a promisified superagent function looks like: ```js var Promise = require('promise'); @@ -16,7 +15,7 @@ request.get('http://google.com') }); ``` -from : https://www.npmjs.com/package/superagent-promise +From: https://www.npmjs.com/package/superagent-promise Here's a more 'nested' example of Promises, which also using `Promise.denodeify` to convert callback-style async functions into promise-style async functions: diff --git a/async/testing.md b/async/testing.md deleted file mode 100644 index 59039de..0000000 --- a/async/testing.md +++ /dev/null @@ -1,40 +0,0 @@ -Let's say we want to test and write an asynchronous function `readJson`, which given a path to a JSON file returns the object represented by the file. - -Our initial approach might look something like: - -```js -test('reads a json file', function (t) { - var path = __dirname + '/data.json' - var object = readJson(path) - t.ok(object) - t.end() -}) -``` - -However if we read our file asynchronously with `fs.readFile`, it's impossible for `readJson` to return synchronously. This is because `fs.readFile` is async: the filesystem read takes time and subsequent lines of code will be run before the contents of the file are ready to be used. - -In synchronous code - -* to send data to the caller we use `return data`. -* to send an error to the caller we use `throw err`. - -In asynchronous code - -* to send data to the caller we use `callback(null, data)`. -* to send an error to the caller we use `callback(err)`. - -This means `readJson` must also take a callback! - -Let's try again: - -```js -test('reads a json file', function (t) { - var path = __dirname + '/data.json' - readJson(path, function (err, object) { - t.error(err) - t.ok(object) - t.end() - }) -}) -``` - diff --git a/async/versus-sync.md b/async/versus-sync.md deleted file mode 100644 index 3df4d34..0000000 --- a/async/versus-sync.md +++ /dev/null @@ -1,36 +0,0 @@ -Every function in JavaScript is either synchronous or asynchronous. It's important to understand the difference because synchronicity defines how the function behaves to the code that calls it. When your code calls a _synchronous_ function, the function makes your code wait until it's finished before letting the next line run (also called _blocking_). This is true for most of the functions you've called so far, and likely all of the functions you've written so far. An _asynchronous_ function returns control to your code right away while it continues to do its work. This allows your code and the function to be working at the same time, asynchronously. Here are some examples: - -```js -console.log('before') -synchConsoleLog('working') // synchronous function -console.log('after') -``` - -As you would expect, the output to the console will look like: - -``` -before -working -after -``` - -Now let's consider an async example: - -```js -console.log('before') -asyncConsoleLog('working') // async function -console.log('after') -``` - -Depending on how long `asyncConsoleLog` takes to execute, the output of this could be: - -``` -before -after -working -``` - -Async functions are appropriate when they are going to take a long time to complete, so the calling code isn't blocked. It turns out that it takes a relatively long time to read or write to the filesystem (the hard drive) and the network (e.g. sending an HTTP request). In these cases, it's common to use async functions. - -The calling code often needs to know when the async function has finished its work. It's also common for the async function to return something (a result, error code or status change) which the calling code needs. In JavaScript, there are a number of different ways to approach this issue: callbacks, promises, and generators. We'll get to promises (and maybe generators) later in the course, but callbacks are the easiest to understand and very common. - diff --git a/command-line/aliases.md b/command-line/aliases.md index 61428fe..b43e9a3 100644 --- a/command-line/aliases.md +++ b/command-line/aliases.md @@ -1,18 +1,30 @@ +# Command Line Aliases + If you have a command you run often, you might like to make a short-cut name for it. Examples of commands that might be useful to have short-hands for: + - `git checkout origin master` - `cd ~/projects/EDA` - `git log --graph --stat` - `ps auxw | grep ...` (where ... is some process you're searching for) -You can create aliases in your `~/.bashrc` (or `~/.zshrc` file if you're using zsh) +This is how you create them: -They look like this : - -```bash -alias gcom="git checkout origin master" -alias eda="cd ~/projects/EDA" +```sh +alias gcm="git checkout origin master" +alias eda="cd ~/workspace" alias glog="git log --graph --stat" alias findps="ps auxw | grep" -``` \ No newline at end of file +``` + +Now to run `git checkout origin master` you can simply type `gcm` by itself. + +To make sure your aliases are available after you reboot, you can create them in your `~/.zshrc` if you're using the Zsh shell or in your `~/.bashrc` file if you're using the Bash shell. + +To see which aliases have already been created, run the `alias` command by itself. If you're looking for a specific alias, you can `grep` it. For example, to look for an alias that has _checkout_ somewhere in it, try this: + +```sh +alias | grep checkout +``` + diff --git a/command-line/shell-scripts.md b/command-line/shell-scripts.md index 998fb8e..12d267c 100644 --- a/command-line/shell-scripts.md +++ b/command-line/shell-scripts.md @@ -1,6 +1,8 @@ -If you want to do anything more complex that a single command, like including some conditional logic, or loops, you a shell script is what you want. +# Shell scripts -Make a file called `findTrailingSpace` +If you want to do anything more complex that a single command, like including some conditional logic, or loops, a shell script is what you want. And you can create them in JavaScript. + +Make a file called `findTrailingSpace`: ```js #!/usr/bin/env node @@ -34,26 +36,27 @@ fs.readFile( targetFile, 'utf8', function(err, data) { ``` -You can run this by running `node findTrailingSpace somefile` - in this mode this is a javascript script. -Notice unix doesn't care you didn't put `.js` on the end of your filename... while file extensions are polite, if you don't add them, it just doesn't care. +You can run this by running `node findTrailingSpace somefile`. In this mode, this is a JavaScript script. Notice that Unix doesn't care that you didn't put `.js` on the end of your filename. While file extensions are polite, if you don't add them, your shell doesn't care. -To make this a full shell script we want to make it executable (as in can run it without calling node in front of it all the time) +To make this a full shell script, we want to make it executable so we can run it without including `node` in front of it all the time. -Do this by running: +Make it executable by running: -``` +```sh chmod +x findTrailingSpace ``` -(where +x means 'add executeable'. Run `man chmod` to read more about what chmod is about) +`+x` means 'add executeable'. Run `man chmod` to read more about what chmod is about. -Now the terminal will read the first line, determine you want to run the contents with node, so we can run our script by just calling: +Now the shell will read the first line (called a hashbang or shebang) to find out what to run the rest of the script with; `node` in our case. Now we can run our script by calling: ``` ./findTrailingSpace somefile ``` -Extras for experts: -- link the concept of an alias and a script so you can call the script from anywhere -- read about unix _path_ and how to put your script in the path -- check out this link for some more interesting shell scripts [Cool shell scripts](http://intuitive.com/wicked/wicked-cool-shell-script-library.shtml), try and implement them yourself! \ No newline at end of file +More to consider: + +- Link the concept of an alias and a script so you can call the script from anywhere. +- Read about the Unix _path_ and how to put your script in the path. +- Check out this link for more interesting shell scripts: [Cool shell scripts](http://intuitive.com/wicked/wicked-cool-shell-script-library.shtml). Have a go at implementing them yourself. + diff --git a/culture/challenges.md b/culture/challenges.md deleted file mode 100644 index 037f473..0000000 --- a/culture/challenges.md +++ /dev/null @@ -1,9 +0,0 @@ -The challenges at Dev Academy are made for learning. Completing things is very satisfying, but in this course you will not have time to finish everything. Side note: the same is true in life. - -``` -Completion !== Learning -``` - -It's important to pay attention to your learning and work on how you most effectively and efficiently learn. You will need to prioritise what you spend you time on. Specifically, we'll be supporting you to ask: - -> Is this advancing my learning? diff --git a/culture/opensource.md b/culture/opensource.md index a35d6dd..e062509 100644 --- a/culture/opensource.md +++ b/culture/opensource.md @@ -1,41 +1,43 @@ +# Open Source + It's time to give back to the community! Here we present some thoughts designed to guide your first contributions to open source software. -### Be respectful +## Be respectful This should underpin everything you do when working with projects and their maintainers. Remember ***IKE***. These people give much of their time and patience to help their community: don't make their life harder! Say, "thank you". -### Read contribution guidelines and documentation +## Read contribution guidelines and documentation We can't stress this enough. If you see guidelines, follow them _even if they're different to what you normally do_. If the maintainers want semicolons, use semicolons! If they want nine spaces in every indent, that's up to them. Your job isn't to change their minds and make them see the One True Way to format code. -### Be precise +## Be precise Your contribution will be examined by others. Make sure you've spell-checked and formatted documentation. Check for broken links. Test code. -### Compare with other contributions +## Compare with other contributions If you're not sure how to format your pull request or issue, look at what others have done. Try to gauge what the minimum standard for contribution is, and exceed it. -### Make sure the tests still pass +## Make sure the tests still pass If a project has unit tests, _run_ them before submitting your PR. Make sure you didn't break something! -### It's not about you +## It's not about you Sometimes you might get an answer to a question or a pull request that strikes you as abrupt or even rude: chances are, it's not about you. Some projects receive hundreds, even thousands of issues and PRs. The maintainers might just be trying to get through the day as quickly as possible, and sometimes that bleeds out into frustration. Remember, text is low-fidelity communication: maybe some context was lost between the two parties? -### Except maybe when it is about you +## Except maybe when it is about you Everybody brings something different to a project. Don't be afraid to suggest something new, _especially_ if you can back it up with a contribution (i.e. if you fix the problem you're pointing out). -### Resources +## Resources - [Trending in open source](https://github.com/trending) - GitHub's list of trending projects - [14 Ways to Contribute to Open Source without Being a Programming Genius or a Rock Star](http://blog.smartbear.com/programming/14-ways-to-contribute-to-open-source-without-being-a-programming-genius-or-a-rock-star/) @@ -43,3 +45,4 @@ Everybody brings something different to a project. Don't be afraid to suggest so - [The Beginner’s Guide to Contributing to Open Source Projects](https://blog.newrelic.com/2014/05/05/open-source_gettingstarted/) - [CodeMontage](https://www.codemontage.com/) - community-driven projects for NPOs - [CodeTriage](https://www.codetriage.com/) + diff --git a/culture/pairing-intro.md b/culture/pairing-intro.md deleted file mode 100644 index 97b0bce..0000000 --- a/culture/pairing-intro.md +++ /dev/null @@ -1,52 +0,0 @@ -Pair programming is an agile software development technique in which two programmers work as a pair together on one workstation. One, the driver, writes code while the other, the navigator, focuses on the bigger picture, and immediately spots mistakes. - -Together, the programmers help each other hold strong attention on the task. - -It is a simple but very effective tool. - -Watch Fiona and Semira's explanation for an explanation of how to pair program. - -Then watch Codr.tv's episode on Pair Programming to hear about how Pairing is used as a tool in the industry. - - -## Environment - -The options we've found for pairing, in order of effectiveness, are: - -1. Pair in person -2. Video call while working collaboratively on a remote computer such as Cloud9. -3. Video call with screen sharing (Skype, Google Hangouts, appear.in, etc.) - **If you can't meet up in person, and you don't have adequate internet connection for options 2 or 3, you won't have adequate communication lines to pair program** - -Instead, you can get some of the benefits with: - -1. Phone call and slack to discuss approaches, ideas and issues. -2. Share pseudocode and code on slack. - - -## Prerequisites - -* Something to work on together - - -## When pairing: - - - First, check-in with your pair - - Assign roles (driver vs navigator) - - Explain your thinking in a clear concise manner - - Keep a timer, to monitor how long you have been in a certain role - - -## Capabilities - -You are comfortable: - - - taking time to check in with another person before coding together - - understanding how to use pair programming effectively - - -## Resources - - - [Pair Programming - Fiona and Semira @ Generation Code (Video)](https://www.youtube.com/watch?v=vgkahOzFH2Q). Their video may seem silly, but the points they touch are very important, and we see the pitfalls they highlight happening on the course all the time. - - [Codr.tv - Pair Programming (Video)](https://www.youtube.com/watch?v=5ySLQ5_cQ34) - diff --git a/culture/researching-tools.md b/culture/researching-tools.md deleted file mode 100644 index 2afdc93..0000000 --- a/culture/researching-tools.md +++ /dev/null @@ -1,4 +0,0 @@ -Being curious about the differences between various setups and tools is a healthy pattern to cultivate. -It's easy to avoid tools because they sound complex. -Use the skills you've learned about time-boxing to learn about a new tool if you're not familiar with it. -Try it out, maybe copy some code or do a bit of a tutorial, but make sure you get to writing real code as fast as possible. diff --git a/culture/style-guides.md b/culture/style-guides.md deleted file mode 100644 index ff66af0..0000000 --- a/culture/style-guides.md +++ /dev/null @@ -1,14 +0,0 @@ -Software projects commonly require developers to write code that conforms to a specific style. A style guide specifies how the code should be formatted, often in excrutiating detail. Writing code that conforms to a style guide has the following advantages and is strongly recommended: - * Code written by someone else that conforms to a familiar style will be more readable than code that does not. - * Your brain has powerful pattern matching capabilities - if the code is well-formatted and in a familiar style you will be able to spot errors **much faster** than if it wasn't well-formatted. - * Style guides have rules that catch common bugs. - * Developers use tools to automate the process of formatting and checking code to see if it conforms to a style (linting). - -Three JavaScript style guides in common usage are: - * [AirBnB Style Guide](https://github.com/airbnb/javascript) - * [Google Style Guide](https://google.github.io/styleguide/javascriptguide.xml) - * [Standard](https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style) - -## Resources - - * [Douglas Crokford: Programming Style & Your Brain](https://www.youtube.com/watch?v=_EANG8ZZbRs) diff --git a/databases/foreign-keys.md b/databases/foreign-keys.md deleted file mode 100644 index 6747838..0000000 --- a/databases/foreign-keys.md +++ /dev/null @@ -1,2 +0,0 @@ -A foreign key is a field in a table which references the primary key of another table so we might have Person [id, name] and Pet [id, name, person_id]. -In this case the field person_id on Pet is a foreign key which references the primary key on Person (id). \ No newline at end of file diff --git a/databases/intro.md b/databases/intro.md deleted file mode 100644 index d58fbc6..0000000 --- a/databases/intro.md +++ /dev/null @@ -1,79 +0,0 @@ -Databases make it easy for applications to save and retrieve data. They allow the data to be accessed by multiple users and potentially many applications while maintaining performance. - -There are different kinds of databases. They vary based on how they store data, which can be advantageous to different types of apps depending on the data it operates on and how it needs to be structured. Examples of these database types include: relational, document, object, and graph. We'll focus on relational databases because they are very common and are appropriate for many types of applications. - - -### Files versus servers - -Databases may run on the same computer as the web server or on a different one. Regardless, it is an explicitly different service. In the same way a web server is an application waiting for HTTP requests, a database server is an application waiting for data-related requests. Database services require credentials in order to connect to them. So before you can store or retrieve any data to a database, you must first create a connection using predefined credentials. Examples of database servers, also called Database Management Systems (DBMS) include: Oracle, MySQL, PostgreSQL and MS SQL Server. These are all relational DBMS, or RDBMS. - -There are also some file-based relational databases, such as Microsoft Access and SQLite. These are appropriate when our application is only used by one user at a time because there isn't a service managing the data. However our application will access the data the same way it would if we were using an RDBMS. There are significant disadvantages to using file-based databases and they should normally not be used with production web applications. However, they are useful during development and for single-user applications, such as mobile apps. - - -### Structured storage (relational) - -Relational data is stored in a structured way so it can be saved and retrieved easily. Fortunately you are already familiar with a structure very similar to databases: spreadsheets. While databases and spreadsheets are very different, there are enough similarities in how they conceptualise data that's it's useful to compare them. - -**Entities**, also called tables, are similar to a single sheet of a spreadsheet. Each database will have at least one of these, but often has many. An example of an entity is: `Users`. - -**Fields**, also called columns, are similar to the the vertical lines in the sheet of a spreadsheet. Each entity will have at least one field. Examples of fields are: `first_name`, `last_name` and `username`. There are some special fields we'll cover later. - -**Records**, also called rows, are similar to the horizontal lines in the sheet of a spreadsheet. An entity will only have records when there is data stored. Until then, there are no records. An examples of a record is: 'Bernie', 'Sanders', 'burningsand'. - - -### Schema versus records - -A database is made up two kinds of information: data and metadata. Data is the actual data being stored - 'Bernie', 'Sanders' and 'burningsand' in the example above. Metadata is the information about the data. Entities and fields define the kind of data being stored: first name, last name, and usernames of Users. It's important that you keep these concepts separate when you think about databases. - - -### Data operations - -After making a connection, you will perform your operations. Most databases permit 4 different types of operations and a very common mneumonic to refer to them is CRUD: create, read, update, and delete. Each of these operations represent something done on a piece of data, also called a record. - -* **Create**: a new record is saved. -* **Read**: an existing record is retrieved. -* **Update**: an existing record is changed (edited). -* **Delete**: an existing record is removed. - - -### Structured Query Language (SQL) - -SQL is the language we use to perform CRUD operations on relational databases. Here are some examples of SQL statements that perform CRUD operations: - -**Create** - -```sql -INSERT INTO Users (id, firstName, lastName, username) -VALUES (123, 'Brendan', 'Eich', 'beich'); -``` - -**Read** - -```sql -SELECT firstName, lastName FROM Users; -``` - -**Update** - -```sql -UPDATE Users -SET firstName='Haskell', lastName='Curry', username='hascurry' -WHERE id=10; -``` - -**Delete** - -```sql -DELETE FROM Users WHERE id = 123; -``` - - -## Database maintenance - -There are a number of tools you can use to manage your databases. Some are graphical and some are libraries you can automate with code. The graphical tools are specific to the database engine you're using, but the libraries can often work with a number of different similar databases (e.g. RDBMS). - -**Migrations** provide an automated way to create, modify and undo changes to the database schema. -**Seeding** provides an automated way to populate the database with data. These are useful when setting up a new development environment and doing deployments. - -We'll be using [Knex.js](https://knexjs.org) as a library to perform database operations and database maintenance tasks. Review the [Knex.js documentation on migrations](https://knexjs.org/#Migrations) and [schema building](https://knexjs.org/#Schema-Building) to create migrations that will establish the database schema. - diff --git a/databases/joins.md b/databases/joins.md index 06e1d55..ecd243a 100644 --- a/databases/joins.md +++ b/databases/joins.md @@ -1,3 +1,4 @@ +# Joins Imagine I wanted to find the names of all the pets who belonged to Jane. This could be done with two queries diff --git a/databases/knex-joins.md b/databases/knex-joins.md deleted file mode 100644 index f4abc31..0000000 --- a/databases/knex-joins.md +++ /dev/null @@ -1,121 +0,0 @@ -### Combining tables for fun and profit - -Sometimes we need information from more than one table. If we keep our users in one table, and our user demographic data in another, we need some way to associate (say) a user's name with their age: - -***users*** - -| id | name | -|:---|:---------------| -| 8 | Orinocco | -| 12 | Tomsk | -| 3 | Uncle Bulgaria | - -***user_demographics*** - -| id | user_id | age | -|:---|:--------|:----| -| 1 | 8 | 3 | -| 2 | 12 | 4 | -| 3 | 3 | 61 | - -A **join** allows us to combine the information based on the values in a column that exists in both tables, in this case combining values when `id` is equal to `user_id`: - -| name | age | -|:---------------|:----| -| Orinocco | 3 | -| Tomsk | 4 | -| Uncle Bulgaria | 61 | - - -### A nod to normalisation - -The question you're probably asking is, "Why not put all the information in one table to begin with?" Well, several reasons, centering around a concept called _normalisation_. This is a huge topic in itself, but can be summarised at a beginning level by saying, "Keep information in lots of small tables and link them to each other using unique IDs." This has a number of benefits including reducing redundancy, ease of adding new types of data, and reducing complexity. - - -### Knex joins - -Using Knex.js we can perform joins without having to know the SQL syntax for the query: - -```js -knex('dogs') - .join('breeds', 'dogs.breed_id', '=', 'breeds.id') - .select('dogs.name', 'breeds.name as breed') -``` - -In raw SQL this translates to: - -```sql -SELECT dogs.name, breeds.name AS breed -FROM dogs -INNER JOIN breeds ON dogs.breed_id = breeds.id -``` - -***dogs*** - -| id | name | breed_id | -|:---|:-------|:---------| -| 1 | Daisy | 5 | -| 2 | Dexter | 3 | -| 3 | Clarry | 2 | - -***breeds*** - -| id | name | -|:---|:----------------------| -| 1 | Boxer | -| 2 | Spoodle | -| 3 | King Charles Cavalier | -| 4 | Bulldog | -| 5 | Mutt | - -| name | breed | -|:----------|:----------------------| -| Daisy | Mutt | -| Dexter | King Charles Cavalier | -| Clarry | Spoodle | - -Note a few things about the above result: - - 1. Not _all_ of the dog breeds are listed: only those that correspond to the dogs in the first table - 2. Only the columns we asked for are returned, and they are labelled `name` and `breed`. - - -### Name conflicts - -Let's talk about that second point for a moment. Why do we use this syntax? -```js - .select('dogs.name', 'breeds.name as breed') -``` -The trick is, Knex returns column names as object properties. What's wrong with this picture? -```js - [ - { - name: 'Daisy', - name: 'Mutt' - } - ] -``` -Of course, we can't have an object with two properties the same, so what actually happens is the second one gets overwritten: -```js - [ - { - name: 'Mutt' - } - ] -``` -Obviously that's not what we want! The solution is to provide another name, an _alias_, for any properties that conflict in this way. We can write `'tablename.columnname as foobar'` to achieve this. In the example above, our output from Knex looks like so: -```js - [ - { - name: 'Daisy', - breed: 'Mutt' - }, - { - name: 'Dexter', - breed: 'King Charles Cavalier' - } - ] -``` -So if we were to describe the above query in English we could say: - -"Join the dogs table and the breeds table where the breed id matches. Then return the data in two columns: "name" (the name column in the dogs table) and "breed" (the name column in the breeds table)." diff --git a/databases/knex-keys.md b/databases/knex-keys.md deleted file mode 100644 index 35e4edd..0000000 --- a/databases/knex-keys.md +++ /dev/null @@ -1,115 +0,0 @@ -### A key, you say? - -Keys are integral to Relational Database Management Systems (RDBMS). Each _record_ or _row_ can contain one or more keys, and there are several different types. - -Records can be identified either by a single key or a combination of keys. Often, but not always, they'll be numbers. There are two types we'll concern ourselves with for now: **primary** and **foreign** keys. - - -### Primary keys - -Typically your `id` column will be a primary key. They have a _unique constraint_, which means that each value must be unique. You can't have two 1's, three 2's, etc. Imagine the chaos if the users in your database could share user IDs! - -Here's a Knex.js migration that creates a simple table with a primary key: - -```js -exports.up = function (knex, Promise) { - return Promise.all([ - knex.schema.createTable('users', function (table) { - table.increments('id').primary() - table.string('name') - }) - ]) -} - -exports.down = function (knex, Promise) { - return Promise.all([ - knex.schema.dropTable('users') - ]) -} -``` - -***users*** - -| id (PK) | name | -|:--------|:-----------| -| 1 | basie | -| 2 | fitzgerald | -| 3 | coltrane | -| 4 | thelonious | - -Primary keys can't be null or 0. Every record in a table with a primary key has to have a key assigned. The `.increments()` function above just makes sure that when you add a new row, an `id` will be assigned with the value of the highest existing `id` + 1. - - -### Foreign keys - -Often we'll need to relate a record in one table to a record in another. Foreign keys link records from different tables together. Using _constraints_, they can help maintain the integrity of the data and enable joins to combine tables. - -Here's how Knex defines foreign keys: - -```js -exports.up = function (knex, Promise) { - return Promise.all([ - knex.schema.createTable('dogs', function (table) { - table.increments('id').primary() - table.string('name') - table.integer('breed_id').references('breeds.id') - }), - knex.schema.createTable('breeds', function (table) { - table.increments('id').primary() - table.string('name') - }) - ]) -} - -exports.down = function (knex, Promise) { - return Promise.all([ - knex.schema.dropTable('dogs'), - knex.schema.dropTable('breeds') - ]) -} -``` - -Notice the `.references('breeds.id')`? That tells the database that we want `dogs.breed_id` to refer to `breeds.id`: we're linking the two tables together using `breed_id` as the key. - -***dogs*** - -| id (PK) | name | breed_id (FK) | -|:--------|:-------|:--------------| -| 1 | Daisy | 3 | -| 2 | Clarry | 2 | - -***breeds*** - -| id (PK) | name | -|:--------|:--------| -| 1 | Boxer | -| 2 | Spoodle | -| 3 | Mutt | - -Put another way, `breed_id` is a foreign key that references `id` on the `breeds` table. - - -### Constraints - -We've touched on the _unique constraint_ that applies to primary keys (no two can be the same value). Foreign keys can have constraints too, that define what should happen when an attempt is made to remove or alter the record that the key is pointing to. - -Take the above table for example. Say someone tries to delete the 'Mutt' row in the `breeds` table, with `id` 3. We already have a record that refers to that row: 'Daisy' in `dogs` would be left without a breed! This seems like a bad thing, and it is. We don't want IDs that point off into nowhere, referring to no record. If someone later managed to add a completely different breed having an `id` of 3, Daisy's breed would be changed without anyone asking her permission. - -The solution is to add a constraint defining what should happen if a breed is deleted. We call this constraint _ON DELETE_. There are several possible values for the constraint. Two of the most important are _RESTRICT_ and _CASCADE_. - -RESTRICT means that the attempt to remove the 'Mutt' record will _fail_ if any of the records in the `dogs` table are mutts. Each dog would have to have their breed changed before the attempt to delete 'Mutt' could succeed. - -CASCADE means that all dogs that are mutts will be deleted when the 'Mutt' record is deleted! For obvious reasons, be careful with this one. - -We can also apply similar values to an _ON UPDATE_ constraint, which as you might have guessed defines what the database should do when a record in `breeds` is changed, but not deleted. - -Here's how Knex handles these constraints: - -```js - table.integer('breed_id') - .references('breeds.id') - .onDelete('RESTRICT') - .onUpdate('CASCADE') -``` - -In other words, when someone tries to remove a breed that is referenced in `dogs`, don't allow it; when someone merely updates a breed, the change spreads to all dogs of that breed. For example, if 'Mutt's `id` was changed from 3 to 4, Daisy's `breed_id` would change to 4 as well. diff --git a/databases/knex-routes.md b/databases/knex-routes.md deleted file mode 100644 index 7e9e4fd..0000000 --- a/databases/knex-routes.md +++ /dev/null @@ -1,88 +0,0 @@ -When we start out with Express, we often create routes that show static (unchanging) data, or we've used them to load and save from the filesystem. We can use a very similar layout to load and save data from a database using Knex.js. - - -### Promises - -The main difference of course is that Knex functions return promises. We won't actually have any data to work with unless we wait for the promises to _resolve_ or _reject_. For example, this sort of thing won't work: - -```js -app.get('/users', function (req, res) { - var users = knex('users').select() - res.send(users) -} -``` - -Instead, we'll need to make use of the `.then()` and `.catch()` functions to ensure that the data is available for us to use (and grab any errors that might occur): - -```js -app.get('/users', function (req, res) { - knex('users') - .select() - .then(function (data) { - res.send(data) - }) - .catch(function (err) { - console.error(err.message) - res.status(500).send("Couldn't show you the users!") - }) -} -``` - -### Extracting the database details to one place - -Following the [Single Responsibily Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), it's much cleaner to have the routes focus on the request and response and extract the details of database access into a separate module. Here's how you could extract them: - -```js -// queries.js - -var development = require('./knexfile').development -var knex = require('knex')(development) - -function getUsers () { - return knex('users').select() -} - -// An example user object: {name: 'feroze', email: 'feroze@gmail.com'} -function insertUser (user) { - return knex('users').insert(user) -} - -module.exports = { - getUsers: getUsers, - insertUser: insertUser -} -``` - -```js -// app.js -// ... - -var queries = require('./queries') - -app.get('/users', function (req, res) { - queries.getUsers() - .then(function (users) { - res.send(users) - }) - .catch(function (err) { - console.error(err.message) - res.status(500).send("Can't display users!") - }) -}) - -app.post('/users', function (req, res) { - var newUser = { - name: req.body.name, // name stored in a submitted form body - email: req.body.email - } - - queries.insertUser(newUser) - .then(function () { - res.sendStatus(200) - }) - .catch(function (err) { - console.error(err.message) - res.status(500).send("Couldn't insert a new user.") - }) -}) -``` diff --git a/databases/relationships.md b/databases/relationships.md deleted file mode 100644 index f572afa..0000000 --- a/databases/relationships.md +++ /dev/null @@ -1,98 +0,0 @@ -Different types of databases represent their records in different ways. For example, document databases use _composition_, wherein records are represented _inside_ of other entities. An example of this would be the relationship between a `User` and their `Bookmarks`. Composition would place the bookmark data inside the user record perhaps as a property on the users object. - -Relational databases represent their records in separate _tables_ and relationships are established between tables. In our bookmarks example, there would be two tables: users and bookmarks. Each bookmark record would include a `user_id` field that refers to the `id` field of an associated record in the users table. - -``` -+--------------------+ +-------------+ -| Users | | Bookmarks | -+--------------------+ +-------------+ -| id |<--- | id | -| name | \ | link | -| address | ---| user_id | -+--------------------+ +-------------+ -``` - -Modern databases are highly optimised to perform fast queries across multiple tables at once - these are called joins. - - -### Types of relationship - -The relationship between tables is often described using broad _types_ that reflect a relationship modelled on 'real life'. These are usually described as _one-to-one_, _one-to-many_, and _many-to-many_. - -One of the canonical examples is the relationship authors have with books: for example, one book may have many authors, and one author may have written many books. We often say an author _HAS MANY_ books, and a book _HAS MANY_ authors. (Even if it doesn't, it _could_!) - - -### One to one - -A user _HAS ONE_ profile. - -***users*** - -| id | username | -|----|------------| -| 1 | xkcd | -| 2 | smbc | -| 3 | rms | -| 4 | greenblatt | -| 5 | gosper | - -***profiles*** - -| id | website | profile_image | user_id | -|----|----------------------|---------------|----------| -| 1 | https://xkcd.com | randall.jpg | 1 | -| 2 | https://stallman.org | rms.jpg | 3 | - -Each `user_id` will occur only once within the `profiles` table. - - -### One to many - -A user _HAS MANY_ blog posts. Even if they've only written one so far, they _could_ have thousands! So we think of the relationship as _one-to-many_. - -***users*** - -| id | username | -|----|------------| -| 1 | xkcd | -| 2 | smbc | -| 3 | rms | -| 4 | greenblatt | -| 5 | gosper | - -***posts*** - -| id | title | user_id | -|----|-------------------|---------| -| 1 | Thing Explainer | 1 | -| 2 | The GNU Manifesto | 3 | -| 3 | GNU Emacs Manual | 3 | - -Notice that `user_id` is not unique in the `posts` table: it can appear as many times as each user has posts. - - -### Many to many - -In our hypothetical system, much like Facebook, users can have 'friends'. There is practically no limit on the number of friends a user can have. A user _HAS MANY_ friends, and each friend might have many friends. - -***users*** - -| id | username | -|----|------------| -| 1 | xkcd | -| 2 | smbc | -| 3 | rms | -| 4 | greenblatt | -| 5 | gosper | - -***friends*** - -| id | user_id | friend_id | -|----|---------|-----------| -| 1 | 4 | 5 | -| 2 | 3 | 4 | -| 3 | 4 | 3 | -| 4 | 5 | 4 | -| 5 | 1 | 2 | - -Here again, the same `user_id` can appear more than once, but it can also appear as a `friend_id`. We don't need the user's username to make the friend connection. diff --git a/databases/sql-intro.md b/databases/sql-intro.md index 3648df8..cdf7874 100644 --- a/databases/sql-intro.md +++ b/databases/sql-intro.md @@ -17,4 +17,5 @@ WHERE id=123; ``` Delete -`DELETE FROM Users WHERE id=123` \ No newline at end of file +`DELETE FROM Users WHERE id=123` + diff --git a/dom/dom-manipulation.md b/dom/dom-manipulation.md deleted file mode 100644 index df4a5f1..0000000 --- a/dom/dom-manipulation.md +++ /dev/null @@ -1,6 +0,0 @@ -There are lots of tools for DOM manipulation at your disposal. -For example: - - - Direct (vanilla) JavaScript: `document.body.appendChild(el)` - - JQuery: `$(body).add(el)` - - Many specialised JQuery alternatives diff --git a/environment/deployment.md b/environment/deployment.md deleted file mode 100644 index 2b3417d..0000000 --- a/environment/deployment.md +++ /dev/null @@ -1,19 +0,0 @@ -Deploying a web application is most certainly specific to the environment being deployed to. With that said, it is increasingly common for cloud providers to allow applications to be deployed using Git. - -Some cloud providers, such as Azure, are able to watch our GitHub repo, notice when we push a new commit to a specific branch we define, and clone it for deployment each time we push. Other cloud providers, such as Heroku, allow us to push directly to it. To do so, we just create a `git remote` that points to our account on the cloud platform. These approaches make deployment _really_ easy. - - -### Deploying to Heroku - -These steps assume the file that starts your server is `server.js`. If it isn't, adjust the steps accordingly. The basic steps to deploy to Heroku are: - -* Create an account on heroku.com. -* Install the Heroku Toolbelt. -* Login to Heroku in your terminal with `heroku login`. -* In the folder of your Node app, create the Heroku app with `heroku create YOUR_APP_NAME`. -* Ensure your `package.json` has a `start` script of `node server.js`. -* Ensure you have a `Procfile` whose only line is `web: node server.js`. -* Push your app to Heroku with `git push heroku master`. -* If you experience an error, use `heroku logs`. - -For more information on deploying a Node.js application to Heroku, see the [associated documentation](https://devcenter.heroku.com/articles/getting-started-with-nodejs#introduction). diff --git a/environment/intro.md b/environment/intro.md index c43e99c..e76ae44 100644 --- a/environment/intro.md +++ b/environment/intro.md @@ -1,4 +1,7 @@ +# Environments + It's common to have several different 'environments' that an application is run in. + They are : - dev environment: for building locally and observing - test environment: just for running tests, may have fake test data or a fake database @@ -23,3 +26,4 @@ The package [dotenv](https://www.npmjs.com/package/dotenv) helps us set up envir **VERY IMPORTANT** : make sure you have added `.env` to your `.gitignore` file, otherwise you might accidentally post your API keys on GitHub. Worst case someone will use your keys to move money, post tweets, or max out your credit card. There are bots that trawl GitHub looking for API keys that have been commited by mistake, do not do it! + diff --git a/functional/closure.md b/functional/closure.md index e70828d..af3e24c 100644 --- a/functional/closure.md +++ b/functional/closure.md @@ -1,82 +1,76 @@ +# Closures + A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. -Here's a powerful pattern that is an example of a closure: imagine instead of making a function that just doubles, we could write a function that makes a function that doubles .. or triples, or timeses by anything we want. +Here's a powerful pattern that is an example of a closure: imagine instead of making a function that just doubles, we could write a function that makes a function that doubles or triples, or multiplies by anything we want. ```js -function makeFunctionThatTimesesByN( n ) { +function makeFunctionThatMultipliesByN (n) { var newFunction = function(x) { - return n*x + return n * x } return newFunction } -var double = makeFunctionThatTimesesByN(2) -// imagine what the inside of makeFunctionThatTimesesByN looks like: - // var newFunction = function(x) { - // return 2*x // n = 2 - // } - // return newFunction - -double(15) -// => 30 +var double = makeFunctionThatMultipliesByN(2) -var hexiply = makeFunctionThatTimesesByN(6) -hexiply(7) -// => 42 +// Imagine what the inside of makeFunctionThatMultipliesByN looks like: +// var newFunction = function(n) { +// return 2 * n // n = 2 +// } +// return newFunction +double(15) // returns 30 +var hexiply = makeFunctionThatTimesesByN(6) +hexiply(7) // returns 42 ``` -This is a wicked poweful trick for baking variables into functions, then passing that function around. -For example, we can bake custom callback functions with specific details baked into their recipe, then hand that callback into an async function. +This is a wicked powerful trick for baking variables into functions, then passing that function around. For example, we can bake custom callback functions with specific details baked into their recipe, then hand that callback into an async function. + -#### Example +## Example -In terms of a pizza delivery analogy, the closure would be the "make a home delivery callback function" and the ingredient we would back in would be "persons address" : +In terms of a pizza delivery analogy, the closure would be the "make a home delivery callback function" and the ingredient we would back in would be "persons address". -Robin places an order for a **Margherita**, and gives their address - **234 Aro Street**. Making pizza's is async, so We want to do something like this: +Robin places an order for a **Margherita**, and gives their address - **234 Aro Street**. Making pizza's is async, so We want to do something like this: ```js fs.createPizza( 'margherita', deliverPizza ) ``` -But if deliverPizza is a callback ... that only takes `(err, pizza)` as arguments (where pizza is the result of a successful createPizza). -How do we get the address into the callback?!! +But if `deliverPizza` is a callback, that only takes `(err, pizza)` as arguments (where pizza is the result of a successful `createPizza`). How do we get the address into the callback?!! -WE BAKE IT IN WITH A CLOSURE +We bake it in with a closure. ```js -function makeCustomDeliveryCallback( address ) { - var customDeliveryCallback = function( err, pizza ) { - if (err) // do something! +function makeCustomDeliveryCallback (address) { + var customDeliveryCallback = function (err, pizza) { + if (err) // handle error - deliver( pizza, address ) + deliver(pizza, address) } return customDeliveryCallback } - ``` And use it like this: ```js -var deliverToRobin = makeCustomDeliveryCallback( '234 Aro Street' ) -fs.createPizza( 'margherita', deliverToRobin ) +var deliverToRobin = makeCustomDeliveryCallback('234 Aro Street') +fs.createPizza('margherita', deliverToRobin) ``` - -Final note: typically closures are written more briefly : - +Final note: typically closures are written more briefly: ```js -function makeCustomDeliveryCallback( address ) { - return function( err, pizza ) { - if (err) // do something! - - deliver( pizza, address ) +function makeCustomDeliveryCallback (address) { + return function (err, pizza) { + if (err) // handle error + deliver(pizza, address) } } - ``` -Check out this great article for more detail: https://developer.mozilla.org/en/docs/Web/JavaScript/Closures \ No newline at end of file +Check out this great article for more detail: https://developer.mozilla.org/en/docs/Web/JavaScript/Closures + diff --git a/functional/immutable.md b/functional/immutable.md index 409b94d..19d16ba 100644 --- a/functional/immutable.md +++ b/functional/immutable.md @@ -1,14 +1,22 @@ +# Immutability + Immutability is a pattern which asserts you're not permitted to mutate (change) an object once it's made. -To make a change you need to make a 'new' object, which is a clone with the changes you want / need. -This seems inconvenient, but affords some massive gains in certain contexts (e.g. when you're trying to determining whether anything has changed in a large data structure) +To _change_ and object after it has been created, you must make a 'new' object, which is a clone of the original that includes the changes. + +This seems inconvenient, but affords some massive gains in certain contexts, such as when you're trying to determining whether anything has changed in a large data structure. + +`Immutable` is a popular library to help you achieve this behaviour. + +https://facebook.github.io/immutable-js | https://www.npmjs.com/package/immutable + +It provides objects which have methods you will be familiar with, but are immutable: -https://facebook.github.io/immutable-js/ | https://www.npmjs.com/package/immutable +| Node | Immutable.js | +| -------- | ---------------- | +| `Array` | `Immutable.List` | +| `Set` | `Immutable.Set` | +| `Object` | `Immutable.Map`* | -Immutable.js provides objects which have methods you will be familiar with, but are immutable: +* _Technically, there's a [Map in ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map) which you could read about._ -Node | Immutable.js | notes --------|--------------|----- -`Array` | `Immutable.List` | -`Set` | `Immutable.Set` | -`Object` | `Immutable.Map` | _technically, there's a [Map in ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map) which you could read about_ \ No newline at end of file diff --git a/functional/pure-functions.md b/functional/pure-functions.md new file mode 100644 index 0000000..7d956b0 --- /dev/null +++ b/functional/pure-functions.md @@ -0,0 +1,29 @@ +# Pure Functions + +A pure function is a function which follow a specific set of rules: + +* Will not mutate _any_ of its arguments +* Will not cause _any_ side effects outside of itself +* Will _always_ return the same value given the same arguments + +Here is a simple example: + +```js +const square = x => x * x // ES6 + +function square (x) { // ES5 + return x * x +} +``` + +Impure functions are less predictable. By definition, they mutate something; either something passed to it, or a variable outside of its scope. + +```js +var someThing = [] + +function (x) { + someThing.push(x) // this will mutate someThing outside of the function's scope + return x++ // this will mutate the variable that was passed in +} +``` + diff --git a/functional/pute-functions.md b/functional/pute-functions.md deleted file mode 100644 index eabc15b..0000000 --- a/functional/pute-functions.md +++ /dev/null @@ -1,23 +0,0 @@ -A pure function is a function which takes arguements but which does not mutate any aguements that it's given. -The advantage of pure functions is that whenever you give them a particular variable(s), they will always have the same output and effect. - -```js -const square = x => x*x // ES6 - -function square(x) { // ES5 - return x*x -} -``` - -Functions that are not pure have less predictable effect - by definition, they mutate something, either something it's passed, or some variable outside of it's scope. - -```js -var someThing = [] - -function(x) { - someThing.push(x) // this will mutate someThing outside of the function's scope - - return x++ // this will mutate the variable that was passed in -} - -``` \ No newline at end of file diff --git a/http/networking.md b/http/networking.md deleted file mode 100644 index f2bdeda..0000000 --- a/http/networking.md +++ /dev/null @@ -1,31 +0,0 @@ -A server is often referred to as the physical or virtual machine. It's what responds when we visit a web site, sending us all the information our browser needs to display the site correctly. - -A service: - - - Just an application that runs on a particular computer - - Listens for requests and then serves responses - - A web server is a service which serves web pages - -Network addresses: - - - Same as IP address - - The address of a computer on a network - - An example is 192.168.1.45 - - The internet started running out of the old kind of addresses (IPv4), so now there's IPv6! These addresses look like this: `2001:4860:4860::8888`. They can include letters: `1fff:0:a88:85a3::ac1f`. - -Ports: - - - The particular 'door' at an address - - The connection to the application/service, such as HTTP, that is listening for requests - -``` - IPv4 address port - v v - 192.168.20.30:80 - 192.168.20.30:3000 - - IPv6 address port - v v - [2001:4860:4860::8888]:80 -``` - diff --git a/http/params-intro.md b/http/params-intro.md deleted file mode 100644 index b6d2580..0000000 --- a/http/params-intro.md +++ /dev/null @@ -1,50 +0,0 @@ -Params is short for parameters. These are one way to send information in a request. Params can be found in a couple of places and might be named differently depending on your framework. - -There are two kinds of params: - -#### Params in a query - -```js -http://mycats.herokuapp.com/api/v1/cats?name=fluffy+joe&city=wellington -``` - -When the server receives this get request, if the request object is `req`, there will often be a way to access the query params. In Express.js, it's `req.query`, and the object returned would look like this: - -```js -{ - name: 'fluffy joe', - city: 'wellington' -} -``` - -Ref: http://expressjs.com/en/api.html#req.query - -These types of params are used to filter the data returned from an HTTP GET request, not to send data to be saved by the server. - - -#### Params in a route - -e.g. - -```js -http://mycats.herokuapp.com/api/v1/cats/12/edit -``` - -On the server-side, it's common to set up routes to accept parameters. In this example the route definition would be: - -```js -app.get('api/v1/cats/:id/edit', function(req, res) { - console.log(req.params) - //... -}) -``` - -Using Express.js, in the example above `req.params` would return: - -```js -{ - id: 12 -} -``` - -Ref: http://expressjs.com/en/api.html#req.params diff --git a/http/sending-request-url-data.md b/http/sending-request-url-data.md new file mode 100644 index 0000000..bdfa2b5 --- /dev/null +++ b/http/sending-request-url-data.md @@ -0,0 +1,51 @@ +# Sending Request URL Data + +There are two ways to send data in the URL: the query string and route parameters. + +## Query String + +``` +GET http://mycats.herokuapp.com/api/v1/cats?name=fluffy+joe&city=wellington +``` + +When the server receives this GET request, if the request object is `req`, there will often be a way to access the query string. In Express, it's `req.query`, and the object returned would look like this: + +```js +{ + name: 'fluffy joe', + city: 'wellington' +} +``` + +Reference: http://expressjs.com/en/api.html#req.query + +This type of data is used to filter the data returned from an HTTP GET request, not to send data to be saved by the server. + + +## Route Parameters + +Consider this example: + +``` +GET http://mycats.herokuapp.com/api/v1/cats/12/edit +``` + +On the server-side, it's common to set up routes to accept parameters. In this example the route definition would be: + +```js +app.get('api/v1/cats/:id/edit', (req, res) => { + console.log(req.params) + //... +}) +``` + +Using Express in the example above, `req.params` would return: + +```js +{ + id: 12 +} +``` + +Reference: http://expressjs.com/en/api.html#req.params + diff --git a/http/side-effects.md b/http/side-effects.md deleted file mode 100644 index 91dfbac..0000000 --- a/http/side-effects.md +++ /dev/null @@ -1,6 +0,0 @@ -A `get` requests is a _read_ operation, and read operations shouldn't have _side effects_ - meaning, nothing should change as the result of just reading it. The parameters sent in the URL are called the _query_ part of the URL and are designed to be used to filter the data the request is requesting - not for saving data on the server. - -If you're sending data to the server to be saved, you expect side effects - the saving of the data. That's fine, you should just be more explicit in your intent - by using `post`. - -There are a lot of _shoulds_ in this topic. These are motivated by being a good HTTP citizen and using the protocol how it was intended. It is certainly possible to write `get` requests that have side effects, but adhering to this guidance will help you maintain expectations with other developers and illustrate your appreciation for the HTTP specification and its authors. This guidance will become even more important when we learn about REST web APIs. - diff --git a/http/status-codes.md b/http/status-codes.md index 4454dbe..0c3b9c4 100644 --- a/http/status-codes.md +++ b/http/status-codes.md @@ -1,54 +1,59 @@ -It is important to always send back the appropriate status codes with your API response. -The following HTTP status codes are possible in response to a request: +# HTTP Status Codes + +It is important to always send back the appropriate status codes with your API response. The following table includes some of the possible HTTP status codes: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HTTP Status CodeStatusDescription
200OK (Immediate response)The request was a success and the response includes the -requested data.
202OK (Immediate response)The request was received and queued for processing, but not yet -processed. Usually in the case of a POST request
400Bad RequestThe request was malformed or unexpected.
401UnauthorizedThe request did not include a valid API key
404Not FoundThe requested resource was not found.
429Too Many RequestsThe rate limit has been reached for this API key.
500Internal Server ErrorThe request could not be fulfilled due to an unexpected -error.
\ No newline at end of file + + HTTP Status Code + Status + Description + + + + + 200 + OK (Immediate response) + The request was a success and the response includes the requested data. + + + + 202 + OK (Immediate response) + The request was received and queued for processing, but not yet processed. Usually in the case of a POST request + + + + 400 + Bad Request + The request was malformed or unexpected. + + + + 401 + Unauthorized + The request did not include a valid API key + + + + 404 + Not Found + The requested resource was not found. + + + + 429 + Too Many Requests + The rate limit has been reached for this API key. + + + + 500 + Internal Server Error + The request could not be fulfilled due to an unexpected error. + + + + + +For a more comprehensive list of status codes: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes + diff --git a/http/the-web.md b/http/the-web.md deleted file mode 100644 index e930721..0000000 --- a/http/the-web.md +++ /dev/null @@ -1,15 +0,0 @@ -The web is a subset of the wider internet. The parts, roughly speaking, are web sites you can visit with your browser. Examples of things on the internet that are not on the web: - - - Email - - Skype - - Bittorrent - -Protocols are agreements that define how different computers communicate with each other. For example: - - - TCP/IP (transmission control protocol/internet protocol) - - VOIP (voice over internet protocol) - - HTTP (hypter text transer protocol) - - FTP (file transer protocol) - -DNS, the Domain Name Service, defines how domain names, such as devacademy.co.nz, are resolved to IP addresses, such as 12.57.211.43. This resolution is required before the computers are able to communicate with each other. - diff --git a/http/verbs.md b/http/verbs.md deleted file mode 100644 index 2f949bd..0000000 --- a/http/verbs.md +++ /dev/null @@ -1,9 +0,0 @@ -The 4 most common HTTP requests (also called _verbs_ and _methods_) are: - -* GET: asks for an existing resource -* POST: sends data to create a new resource -* PUT: sends data to update existing resource -* DELETE: asks for an existing resource to be deleted - -There are a few other HTTP verbs, but these are the important ones for now. - diff --git a/images/paint-by-numbers.jpg b/images/paint-by-numbers.jpg deleted file mode 100644 index 0802164..0000000 Binary files a/images/paint-by-numbers.jpg and /dev/null differ diff --git a/images/redux-overview.jpg b/images/redux-overview.jpg deleted file mode 100644 index 0da7122..0000000 Binary files a/images/redux-overview.jpg and /dev/null differ diff --git a/images/shoulders_of_giants.jpg b/images/shoulders_of_giants.jpg deleted file mode 100644 index d6e82e4..0000000 Binary files a/images/shoulders_of_giants.jpg and /dev/null differ diff --git a/javascript/data-structures.md b/javascript/data-structures.md deleted file mode 100644 index 0f51a6c..0000000 --- a/javascript/data-structures.md +++ /dev/null @@ -1,56 +0,0 @@ -You need to be able to navigate complicated nested data structures. -When you ask questions of servers on the internet, you're going to get complicated responses, like: - -```js -{ - "statusCode": 200, - "path": "users/subscriptions", - "query": { - "basePlan": "standard", - "totalGreaterThan": 400 - }, - "results": [ - { - "id": 201, - "name": "Rinsed Ltd", - "email": "rinsed@gmail.com", - "basePlan": "standard", - "xeroPlan": "starter", - "addOns": { - "gstReview": 20, - "companyAdvice": 75 - } - },{ - "id": 332, - "name": "Loomio Cooperative Ltd", - "email": "accounts@loomio.org", - "basePlan": "social enterprise", - "xeroPlan": "starter", - "addOns": { - "extraSoftware": 10, - "gstReview": 5 - } - } - ] -} -``` - -You might like to play with ways of explore this data structure in the Node REPL. - -Note: REPL stands for "Read Evaluate Print Loop". When you have node installed and you type `node` in your terminal, you'll enter a simple interactive programming sandbox where you can play with JavaScript directly (type Ctrl-C twice to exit.) The console on your browser is another type of a REPL that provides access to the browser's DOM rather than the Node.js library. - -Try **chaining** property calls and navigating the data structure. For example: - -```js -results.query.totalGreaterThan -``` - -If an object is too deep you can also tell it to give you its keys using the method `Object.keys()`. For example: - -```js -Object.keys(response) -Object.keys(response.query) -``` - -You will encounter a lot of objects like this over the next few weeks. It's important to not be scared off, to feel comfortable exploring them. Try different approaches to get information out of objects. - diff --git a/javascript/datatypes.md b/javascript/datatypes.md deleted file mode 100644 index 1108af7..0000000 --- a/javascript/datatypes.md +++ /dev/null @@ -1,11 +0,0 @@ -* Primitives - - Boolean - - Null - - Undefined - - Number - - String -* Objects - - Special types of objects - -The Mozilla Developer Network has a really good [explanation of JavaScript data types](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures). - diff --git a/javascript/es6-syntax-1.md b/javascript/es6-syntax-1.md deleted file mode 100644 index b59929e..0000000 --- a/javascript/es6-syntax-1.md +++ /dev/null @@ -1,120 +0,0 @@ -While exploring the new ES6 syntax, you might consider using the Babel CLI (command line interface) tools. These provide a REPL (read evaluate print loop) interface and let you run files in the terminal. Use npm to install them: - -```sh -npm install -g babel-cli -``` - -See [Babel CLI tools](https://babeljs.io/docs/usage/cli/) for more information. - - -### Modules - -Modules provide a way to separate our code across multiple files. This makes our applications much easier to maintain and easier for multiple developers to work on at the same time. This new language feature does the same thing `module.exports` and `require` perform in the Node.js environment. - -To export values, objects, arrays, function, or pretty much anything from a module, just preface it with `export`. - -```js -// utility.js -export default function joinStrings (s1, s2) { - return s1 + ' ' + s2 -} -``` - -This makes it available to _import_. There are multiple ways to import items from modules. To import default values like the `joinStrings` function above: - -```js -// app.js -import join from 'utility.js' -var combined = join('pretty', 'cool') -``` - -For more information, see [ES6 In Depth: Modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/). - - -### Variable declaration with `let` and `const` - -In ES5, we use `var` to declare variables. Variables declared with `var` are available to the entire function regardless of where it is defined. This is not true for most languages, which have _block-level_ scoping, rather than _function-level_ scoping. `let` and `const` apply block level scoping to JavaScript. This means we can define variables inside `if` statements and `for` loops (and other block constructs) that are not available outside of the blocks they are defined in. `const` defines a variable that cannot be reassigned with a different value. For example: - -```js -function testVar () { - var foo = 44 - if (true) { - var foo = 13 // same variable - console.log(foo) // 13 - } - console.log(foo) // 13 -} - -function testLet () { - let foo = 44 - if (true) { - let foo = 13 // different variable - console.log(foo) // 13 - } - console.log(foo) // 44 -} -``` - -For more information, check out [ES6 In Depth: let and const](https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/). - - -### Arrow functions - -Arrow functions are a new syntax to write anonymous functions. So far we've been writing: - -```js -var fn = function (op1, op2) { - return op1 + op2 -} -``` - -With ES6 arrow functions, we can write: - -```js -const fn = (op1, op2) => op1 + op2 -``` - -It essentially removes the `function` keyword and places the arrow between the parameters and the body of the function. - -Some notes about arrow functions: - -* The parentheses are optional around the parameters if there is only a single parameter. They are required if there are no parameters or more than one. - -* Curly braces are optional when the body of the function can fit on one line. - -* If there are no curly braces, arrow functions automatically return the result of the statement to the right of the arrow. This is called _implicit_ return. - -* If there are curly braces, we still need to use the `return` keyword: - -```js -// Doesn't need return -const fn1 = (op1, op2) => op1 - op2 - -// Needs return -const fn2 = (op1, op2) => { return op1 - op2 } -``` - -For more information, check out [ES6 In Depth: Arrow functions](https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/). - - -### Template Strings - -String interpolation provides a much nicer way to combine strings and values. We're currently used to concatenating strings when we need to combine them: - -```js -var user = {name: 'Kristina'} -var welcome = 'Welcome back ' + user.name + '. Good to see you.' -``` - -The new syntax is easier to read: - -```js -const user = {name: 'Kristina'} -const welcome = `Welcome back ${user.name}. Good to see you.` -``` - -Notice how the string is deliniated with backticks to indicate it is a template string. - -For more information, check out [ES6 In Depth](https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2/). - -There is a lot more about ES6 to learn, but that is enough for now. Feel free to explore - there are a lot of really nice additions. There are really good resources on ES6/2015 online. diff --git a/javascript/first-class-functions.md b/javascript/first-class-functions.md deleted file mode 100644 index 41e0984..0000000 --- a/javascript/first-class-functions.md +++ /dev/null @@ -1,42 +0,0 @@ -An important thing to remember about functions in JavaScript is: *functions are values*. - -This means that functions are treated as first-class citizens, just like numbers and objects. They have all the properties we expect of other objects. Check out Helen Emerson's [article on the subject](http://helephant.com/2008/08/19/functions-are-first-class-objects-in-javascript/) for a more in-depth explanation. - -Let's look at this example: - -```js -// A named function -function triple (x) { - return x * 3 -} - -// An anonymous function -function (x) { - return x * 3 -} - -// An anonymous function assigned to a variable -var triple = function (x) { - return x * 3 -} -``` - -Because the last example uses a variable, you can do some cool things like this: - -```js -var engorgio = triple -var value = engorgio(30) // value is 90 -``` - -Both `triple` and `engorgio` refer to the same function. But the fun does not stop there! We can also pass functions into other functions as arguments. - -A good example of this is the filter function, probably the most basic and useful higher order function. It's a function that operates on an array, and accepts another function as an argument that it uses to return a new filtered version of the array. - -Let's pop over to this repl.it and have a play: [https://repl.it/CGjq](https://repl.it/CGjq/26). - -So, to recap: - -* We can store functions in variables -* We can store functions as properties of other objects -* Functions can have properties -* We can pass functions as arguments into other functions diff --git a/javascript/sets.md b/javascript/sets.md deleted file mode 100644 index e69de29..0000000 diff --git a/mobile/debugging.md b/mobile/debugging.md index c561800..49f9f31 100644 --- a/mobile/debugging.md +++ b/mobile/debugging.md @@ -6,6 +6,7 @@ So what does mobile first actually look like in a development practice context? Luckily we have lots of fabulous tools to help us! + ## Stylesheets Let's just spend a quick moment on stylesheets. @@ -17,6 +18,7 @@ Kotare's final project did a really good job of mobile first approach, - [tandem](https://github.com/Tandem-NZ/tandem/blob/master/public/styles/sass/_desktop.scss) + ## Debugging mobile There are loads of different ways we can debug and play with mobile, the first is obviosuly to shrink our browsers to size. However, that can sometimes not work. @@ -50,7 +52,6 @@ This works for any ios devices, so all the ipads ect, which is SUPER USEFUL! http://appletoolbox.com/2014/05/use-web-inspector-debug-mobile-safari/ - Xcode also has a new simulator, though this is only for iphone 6 and above - open xcode @@ -63,8 +64,10 @@ Pretty much exactly the same applies with Chrome and android devices. In the pho here is a useful blog on how to do this: https://developer.chrome.com/devtools/docs/remote-debugging + ## Extra excitment, demo-ing your mobile things on desktop - Have your iphone plugged in - Open quicktime player on your mac -- select the little arrow on the dropdown, and select your phone \ No newline at end of file +- select the little arrow on the dropdown, and select your phone + diff --git a/oo/classes.md b/oo/classes.md index ef7cfdb..deecc5e 100644 --- a/oo/classes.md +++ b/oo/classes.md @@ -1,11 +1,14 @@ -In Javascript, classes have only just been added with ES6. -Check out the docs here : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes, in particular : +# Classes + +In JavaScript, classes have only just been added with ES6. Check out the docs here: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes, in particular: + - constructor - prototype methods - extends (note sub-classing is another way to say inheritance) - super -#### Using classes in your code + +## Using classes in your code You'll need to transpile (convert) your new ES6 standard code into code that all browsers will support. @@ -30,5 +33,5 @@ var OrangeTree = require('../OrangeTree') import OrangeTree from '../OrangeTree' import {pruneTree} from '../OrangeTree' +``` -``` \ No newline at end of file diff --git a/oo/classical-inheritance-es5.md b/oo/classical-inheritance-es5.md index 0547788..4b7c5c7 100644 --- a/oo/classical-inheritance-es5.md +++ b/oo/classical-inheritance-es5.md @@ -1,7 +1,10 @@ +# Pseudo-classical Inheritance (ES5) + Many programming languages use the concepts of `class`, `subclass` and `inheritance` to assist with code reuse. When we create objects of a particular subclass these objects inherit properties and methods from their parent class. This allows us to write code once on the parent class and have it inherited and reused on its descendants. JavaScript ES5 does not implement "classical inheritance" in the same way as other languages. Instead its common to use "prototypal inheritance" to mimic classical inheritance with constructor functions. Its also possible to use factory functions to implement inheritance. As these are not true classes we sometimes call these "pseudo-classes". The examples below show how to implement the classical inheritance pattern with the tools available in ES5: + ## Prototypal inheritance with constructor functions ```js @@ -60,7 +63,6 @@ console.log(frodoComment === oneRingDiscussion.getCommentAtIndex(0)) console.log(frodoComment instanceof Comment) // true - ``` The code above implements a parent constructor function `Post` and its two child constructor functions `Discussion` and `Comment`. We might imagine that this code drives an online discussion forum. `Post` has three properties `author`, `content` and `createdAt` and one method `getCreatedAt()`. When we define `Comment` and `Discussion` we call the parent constructor method passiing in a reference the current context `this` and the child's `arguments`. This lets `Discussion` and `Comment` inherit `Post`'s properties and the `getCreatedAt()` method (this is equivalent to calling `super` in ES6). Child constructor functions can also implement their own properties and methods. @@ -134,14 +136,14 @@ console.log(frodoComment instanceof Comment) // false console.log(frodoComment instanceof Object) // true - ``` + ## Differences We call Constructor functions using the `new` keyword while we call factory functions like regular functions. Constructor function instances can be checked against their constructor with the `instanceof` keyword while factory function instances are regular `Object` instances. -The more informative `instanceof` behaviour of constructor functions may be useful in codebases where checking the pseudo-class of instances is important for error catching, e.g.: +The more informative `instanceof` behaviour of constructor functions may be useful in codebases where checking the pseudo-class of instances is important for error catching, for example: ```js Discussion.prototype.addComment = function (comment) { @@ -152,6 +154,7 @@ Discussion.prototype.addComment = function (comment) { } ``` + ## Further Information * [http://javascript.crockford.com/inheritance.html](http://javascript.crockford.com/inheritance.html) @@ -162,3 +165,4 @@ Discussion.prototype.addComment = function (comment) { * [Factory constructor pattern](http://javascript.info/tutorial/factory-constructor-pattern) * [Defending constructors](http://www.2ality.com/2013/07/defending-constructors.html) * [instanceof](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/instanceof) + diff --git a/oo/classical-inheritance-es6.md b/oo/classical-inheritance-es6.md index f60a2b8..da1762a 100644 --- a/oo/classical-inheritance-es6.md +++ b/oo/classical-inheritance-es6.md @@ -1,44 +1,46 @@ +# Pseudo-classical Inheritance (ES6) + ES6 introduced the `class` and `extends` and `super` keywords. These keywords provide another way to express [prototypal inheritance](https://developer.mozilla.org/en/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) using a syntax that may be more familiar to developers accustomed to it in many other programming languages. An example is shown below: ## Example ```js class Post { - constructor(options) { + constructor (options) { const { author, content } = options this.author = author this.content = content this.createdAt = Date.now() } - getCreatedAt() { + getCreatedAt () { return this.createdAt } } class Comment extends Post { - constructor(options) { + constructor (options) { super(options) this.likeCount = 0 } - like() { + like () { this.likeCount ++ } } class Discussion extends Post { - constructor(options) { + constructor (options) { super(options) this.title = options.title this.comments = [] } - addComment(comment) { + addComment (comment) { this.comments.push(comment) } - getCommentAtIndex(index) { + getCommentAtIndex (index) { return this.comments[index] } } @@ -54,42 +56,48 @@ const frodoComment = new Comment({ content: 'One idea is to throw it into a volcano. What does everyone think?' }) - console.log(frodoComment.getCreatedAt()) oneRingdiscussion.addComment(frodoComment) console.log(frodoComment === oneRingDiscussion.getCommentAtIndex(0)) // => true - ``` + The code above implements a parent class `Post` and its two child classes `Discussion` and `Comment`. We might imagine that this code drives an online discussion forum. `Post` has three properties `author`, `content` and `createdAt` and one method `getCreatedAt()`. When we define `Comment` and `Discussion` we use the `extends` keword to inherit `Post`'s properties and the `getCreatedAt()` method. These child classes can also implement their own properties and methods. Inside each of the child classes' `constructor()` we can see the usage of `super`: + ```js // class definition -constructor(options) { +constructor (options) { super(options) // more constructor code } - ``` + The `super(options)` call respresents *the parent class's contructor method*: + ```js class Post { - constructor(options) { + constructor (options) { const { author, content } = options this.author = author this.content = content this.createdAt = Date.now() } -// more code + // more code +} ``` + This means that whenever we instantiate a `Comment` or `Discussion` passing in our options object we also register it with `author`, `content` and `createdAt` properties. + ## Applications React.js uses a `Component` class for [one of its methods](https://facebook.github.io/react/docs/reusable-components.html#es6-classes) for creating UI components. + ## Further Information * [MDN - Classes](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) * Dan Abramov outlines some [best practices](https://medium.com/@dan_abramov/how-to-use-classes-and-sleep-at-night-9af8de78ccb4#.wdmybk5py) for using the `class` keyword in JavaScript + diff --git a/oo/constructors.md b/oo/constructors.md index 47e01cd..3c6962c 100644 --- a/oo/constructors.md +++ b/oo/constructors.md @@ -1,13 +1,15 @@ +# Constructors + Constructors are similar to Factory functions but slightly different. -e.g. +For example, ```js -var Person = function(name) { +var Person = function (name) { this.name = name } -Person.prototype.sayHello = function() { +Person.prototype.sayHello = function () { console.log("Hello, I'm " + this.name) } @@ -23,4 +25,5 @@ We call constructors using the keyword `new` which instantiates a new instance o Note we've also extending the Person prototype with a function (`sayHello`). -Constructors are slightly faster than Factory functions, but there are a few gotchas that mean they're currently less popular. \ No newline at end of file +Constructors are slightly faster than factory functions, but there are a few gotchas that mean they're currently less popular. _**LIKE WHAT?**_ + diff --git a/oo/factory-functions.md b/oo/factory-functions.md index f068eab..e3e8b68 100644 --- a/oo/factory-functions.md +++ b/oo/factory-functions.md @@ -1,13 +1,13 @@ -Like a closure, but returns an object. -You can store details, prep the layout, and attach functions to your object. +# Factory Functions + +Like a closure, but returns an object. You can store details, prep the layout, and attach functions to your object. ```js -function personFactory(name) { +function personFactory (name) { return { name: name, age: undefined, - introduceYourself: function() { - return `Hi, my name is ${name}` + introduceYourself: () => `Hi, my name is ${name}` } } } @@ -19,3 +19,4 @@ console.log(vanessa.introduceYourself()) ``` There's a small detail where if you are making more than 10,000 objects with a factory function, you should consider moving to classes, which start to be more performant in that range (more on this later). + diff --git a/oo/intro.md b/oo/intro.md index dfc4072..5a97fc2 100644 --- a/oo/intro.md +++ b/oo/intro.md @@ -1,6 +1,8 @@ -Object Oriented programming (OO) is a pattern of organising code that involves thinking about the things you're dealing as being **instances** of particular objects. +# An Introduction to Object-orientation -We often want to store particular details (**state**) and perform particulr actions (**behvaiour**) which are just relevant to a particular type of this, OO allows us to pull all this together in one place. +Object Oriented programming (OOP) is a pattern of organising code that involves thinking about the things you're dealing as being **instances** of particular objects. + +We often want to store particular details (**state**) and perform particular actions (**behaviour**) which are just relevant to a particular type of this, OO allows us to pull all this together in one place. For example, all instances of a `User` object might have a particular state (e.g. name, email, isAwake) and have particular methods you could call on that user, e.g. if `piet` is an instance of `User`, you could call `piet.getEmail()` or `piet.wakeUp()`, or `piet.introduceYourself(dave)`. @@ -9,15 +11,15 @@ If you're ever wondering which object should own a function, you can ask yoursel > Should this thing know about this concept, is it this object's responsibility? -e.g. Should I be able to ask a Cat what it's email is? ... No, that's that's Owner that has an eamil. I should be able to ask Cat about it's owner, and ask owner about it's email. +For example, should I be able to ask a Cat what its email is? No, it's the Owner that has an email. I should be able to ask Cat about its owner, and ask Owner about its email. -#### Prototype-based OO +## Prototype-based OO -Constructors are the prototype-way to do OO in javascript. +Constructors are the prototype-way to do OO in JavaScript. -#### Class-based OO +## Class-based OO Classes are similar to Constructors, but they have a number of additional features: - **inheritance** : classes can inherit from / extend existing classes @@ -31,3 +33,4 @@ Classes are similar to Constructors, but they have a number of additional featur - instantiate - state + behaviour - prototype (like a template) + diff --git a/oo/methods.md b/oo/methods.md deleted file mode 100644 index 0c43e79..0000000 --- a/oo/methods.md +++ /dev/null @@ -1,2 +0,0 @@ -Functions that belong to instances of classes are called methods. -e.g. A `User` object `dave` has a method on it called `email` which can be called : `dave.email()` \ No newline at end of file diff --git a/oo/the-journey.md b/oo/the-journey.md index a79fa2a..4349863 100644 --- a/oo/the-journey.md +++ b/oo/the-journey.md @@ -286,3 +286,4 @@ const squareClass = new SquareClass(10, 'red') * * + diff --git a/projects/group-projects-introduction.md b/projects/group-projects-introduction.md deleted file mode 100644 index c78b4b2..0000000 --- a/projects/group-projects-introduction.md +++ /dev/null @@ -1,14 +0,0 @@ -Today we will spend a bit of time thinking about how we will build our group projects. You should try to use as much of what you've learned this week in your project. You'll have 3 or 4 people on your team and you're expected to partition the work among team members. Each team member may want to choose a task they are strong in, or a task that will solidify knowledge for them. The rest of the team should support these decisions as much as it makes sense. You may also consider designating certain team members as: Time Keeper and Git Keeper (you can come up with your own inventive names for these positions!) - -You can use today to establish teams and scope out what you're going to build. A teacher should approve your project idea before you begin. During your planning, you should define milestones and (at a minimum) commit to your repo at each milestone. You are expected to build the appropriate parts using Test Driven Development (branch, red, green, refactor, diff, commit). - -Feature freeze is the time when you are not permitted to work on any new functionality. Code freeze is when you're not permitted to make any more changes to your codebase. Feature freeze is at 3:30 and code freeze is at 4pm. Presentations begin promptly at 4:30. Each team member should speak during the presentation. Each team will have 5 minutes to describe what you've built, show a demonstration, and possibly show one piece of code that is particularly interesting. - - -### Team dynamics - -You've been pair programming for a couple of weeks now, but this is the first time you're going to build something on a team. Be sure you remain mindful during your group project. You're going to be under pressure to finish something under a time limit. You're going to want it to be great and something you can be proud of, and this could add to the pressure. You're going to need to depend on your teammates. Sometimes they won't disappoint you, and sometimes they will. How you react is up to you. - -Remember to have **I**ntegrity, **K**indness, and **E**ffort. Be open and honest with yourself and your team. Try to minimize surprises by being transparent. Keep the communication levels high and ask for help when you need it. Focus on setting up your teammates for success. And have fun! - -These group projects are as much about how you work together as what you build. diff --git a/projects/personal-projects-introduction.md b/projects/personal-projects-introduction.md deleted file mode 100644 index 642e5ef..0000000 --- a/projects/personal-projects-introduction.md +++ /dev/null @@ -1,35 +0,0 @@ -> "Whatever course you decide upon, there is always someone to tell you that you are wrong. There are always difficulties arising which tempt you to believe that your critics are right. To map out a course of action and follow it to an end requires courage." ~ Ralph Waldo Emerson - -## Purpose - -Many developers work on side projects as a funnel for both professional development and meaningful play. Some employers (most famously Google) even alot time each month for their employees to work on projects that interest them. It's a great way to cement your understanding of new tools and things we've learned during the first part of the bootcamp. - -It's also a good time to explore _how_ you learn. What works best for you? When you're working alone, how can you make best use of the time to further your understanding? - - -## Tips - - - Explore something you care about. - - Build something you or someone you know would love to use. - - Integrate new tools and techniques as you learn them. - -The most impressive apps that have been developed in this phase were built with continuous improvement in mind. First, create a minimum viable product (MVP) as soon as possible. It doesn't have to be fancy! Early MVP is a powerful tool in developing your project. It provides reassurance ("At least I have _this_ done!") and it can help to keep your scope controlled: not biting off too much work all at once! Your MVP should be fairly simple; once you have your MVP, your project can develop in complexity over the three weeks of Phase 2. - - -## Process - -There will be time set aside each week to work on personal projects, but you may choose to use your own time to work on it as well. At the end of Phase 2 everyone will present their project to the rest of the cohort. - - -## Examples - -Here are some examples from previous cohorts: - - - [Trout-trout](http://trout-trout.herokuapp.com/#!/), an app to track trout caught in a lake -(repo found [here](https://github.com/SamSimmons/garyTrout)) - - - [Schools project](https://github.com/wishmouse/schools) - - - [Hear now gone tomorrow](https://github.com/KeakOne/hearnow-gonetommorow) - - - [Ki Mai](http://ki-mai.herokuapp.com/users) ([github](https://github.com/tony-luisi/ki_mai)), an interactive chat application to aid in learning the Maori language. diff --git a/react/components.md b/react/components.md deleted file mode 100644 index e3c0b25..0000000 --- a/react/components.md +++ /dev/null @@ -1,40 +0,0 @@ -React forces you to think about your user interfaces as sets of _components_: small composable areas of the view. Components are composed in a hierarchical structure with _container components_ acting as parents of _child components_. Each component is made up of the user interface elements (JSX) and data. The guidance is to deconstruct your views into components and understand what data they contain before you begin building your user interface. - -This is an example of a component: - -```js -// Header.jsx -import React from 'react' - -class Header extends React.Component { - render() { - return ( -
-

Header

-
- ) - } -} - -export default Header -``` - -This component will be imported into the app using: - -```js -// App.jsx -import React from 'react' -import Header from './Header' - -class App extends React.Component { - render() { - return ( -
-
-
- ) - } -} - -export default App -``` diff --git a/react/event-delegation.md b/react/event-delegation.md deleted file mode 100644 index e7ac7eb..0000000 --- a/react/event-delegation.md +++ /dev/null @@ -1,69 +0,0 @@ -In order to respond to user events, component functions can be bound to [virtual] DOM events. In this example, an `addToCart` function in the `` component is called when a button is clicked in the `` component. - -```js -// ItemList.js -import React from 'react' -import Item from './Item' - -class ItemList extends React.Component { - - constructor(props) { - super(props) - this.addToCart = this.addToCart.bind(this) - } - - addToCart (itemID) { - console.log(itemID) - } - - render () { - return ( -
- {this.props.items.map((item) => { - return - })} -
- ) - }, -} - -export default ItemList -``` - -Notice how the local `addToCart` function is being passed as a prop to the `` component. Additionally, notice how an `itemID` argument is passed to the `addToCart` function. This is how the parent component knows which item we are adding to the cart. - -```js -// Item.js -import React from 'react' - -class Item extends React.Component { - - constructor(props) { - super(props) - this.handleClick = this.handleClick.bind(this) - } - - handleClick () { - this.props.addToCart(this.props.id) - } - - render () { - return ( -
-

{this.props.name}

- -
- ) - } -} - -export default Item -``` - -The `addToCart` event handler is used directly from `this.props` in Item.js. - diff --git a/react/forms.md b/react/forms.md deleted file mode 100644 index b640215..0000000 --- a/react/forms.md +++ /dev/null @@ -1,195 +0,0 @@ -Sometimes forms in React can feel like a bit of a stumbling block, but they needn't be. Like most of the content you've learned so far, with practice they become far less intimidating! - - -## Where does the data go? - -There are various approaches to handling forms, but mostly they boil down to one decision: where do you want to keep the form data? - - - in _component state_ (controlled components) - - in the _DOM_, using refs (uncontrolled components) - - in the _Redux store_ (if you haven't encountered Redux yet, don't worry about this one!) - -As usual on the Internet, lots of people have very strong opinions about how to write forms! Facebook [recommends](https://facebook.github.io/react/docs/forms.html#alternatives-to-controlled-components) using controlled components for the most part, but not everyone agrees. [This comparison of the approaches](https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/) is a fair summary. - -We suggest not getting too tangled up in the debate. Learn the different ways to work with forms, then pick the one that you think fits your need best. If it ends up not working so well for you, revisit this decision with your team to talk about what could have been improved. - -If you want a rule of thumb, here's one: - - - if your form is relatively simple, try using refs; - - if it's complicated or likely to become so, try using controlled components. - - -## Uncontrolled components - -Here's an example of an uncontrolled component form: - -```js - render () { - return ( -
- - - this.name = name} /> - - -