Insight UBC: Deliverable 1
Goals and specs
1. Add and remove a dataset containing information about UBC courses
Goals and specs
1. Add and remove a dataset containing information about UBC courses
Courses.zip
addDataset(...)
Parse it
Keep data structure in a variable
Save it to disk
Caching
No need to parse again the same dataset.
No need to go to disk on every request
Goals and specs
2. Answer queries about UBC courses.
Goals and specs
2. Answer queries about UBC courses.
Examples:
"what departments have courses with averages higher than 90%?"
"What courses in CPSC have a high fail rate?"
Goals and specs
2. Answer queries about UBC courses.
{
"WHERE":{
"GT":{
"courses_avg":97
}
},
"OPTIONS":{
"COLUMNS":[
"courses_dept",
"courses_avg"
],
"ORDER":"courses_avg"
}
}
Goals and specs
2. Answer queries about UBC courses.
{
"WHERE":{
"GT":{
"courses_avg":97
}
},
"OPTIONS":{
"COLUMNS":[
"courses_dept",
"courses_avg"
],
"ORDER":"courses_avg"
}
}
{ result:
[ { courses_dept: 'epse', courses_avg: 97.09 },
{ courses_dept: 'math', courses_avg: 97.09 },
{ courses_dept: 'math', courses_avg: 97.09 },
{ courses_dept: 'epse', courses_avg: 97.09 },
{ courses_dept: 'math', courses_avg: 97.25 },
{ courses_dept: 'math', courses_avg: 97.25 },
{ courses_dept: 'epse', courses_avg: 97.29 },
{ courses_dept: 'epse', courses_avg: 97.29 },
{ courses_dept: 'nurs', courses_avg: 97.33 },
{ courses_dept: 'nurs', courses_avg: 97.33 } ] }
Goals and specs
2. Answer queries about UBC courses. Queries follow the following EBNF:
QUERY ::='{'BODY ', ' OPTIONS '}'
BODY ::= 'WHERE:{' FILTER '}'
OPTIONS ::= 'OPTIONS:{' COLUMNS ', ' ('ORDER:' key )?'}'
FILTER ::= (LOGICCOMPARISON | MCOMPARISON | SCOMPARISON | NEGATION)
LOGICCOMPARISON ::= LOGIC ':[{' FILTER ('}, {' FILTER )* '}]'
MCOMPARISON ::= MCOMPARATOR ':{' key ':' number '}'
SCOMPARISON ::= 'IS:{' key ':' [*]? inputstring [*]? '}'
NEGATION ::= 'NOT :{' FILTER '}'
LOGIC ::= 'AND' | 'OR'
MCOMPARATOR ::= 'LT' | 'GT' | 'EQ'
COLUMNS ::= 'COLUMNS:[' (key ',')* key ']'
key ::= string '_' string
inputstring ::= [^*]+
Activity #1
We previously discussed about software engineering process and methodologies.
We learned about waterfall, spiral, and the many variations of scrum: XP, kanban, and more.
What would be the most adequate methodology to build Insight UBC? How would you approach tests, documentation, design, and development?
Take a few minutes to discuss this with your classmates!
Activity #2
Now that we have a better idea about what methodologies and approaches to use, discuss with your classmates how you would break the deliverable 1 tasks into user stories.
Project structure: API
export interface IInsightFacade {
addDataset(id: string,
content: string,
kind: InsightDatasetKind):
Promise<InsightResponse>;
removeDataset(id: string): Promise<InsightResponse>;
performQuery(query: any): Promise<InsightResponse>;
listDatasets(): Promise<InsightResponse>;
}
Project structure: API
export interface InsightResponse {
code: number;
body: InsightResponseSuccessBody | InsightResponseErrorBody;
}
export interface InsightResponseSuccessBody {
result: any[] | string;
}
export interface InsightResponseErrorBody {
error: string;
}
export enum InsightDatasetKind {
Courses = "courses",
Rooms = "rooms"
}
export interface InsightDataset {
id: string;
kind: InsightDatasetKind;
numRows: number;
}
Project structure: Testing
it("Test addDataset 204", function () {
let readStream = fs.readFileSync("$PATH_TO_ZIP_FILE").toString('base64');
return facade.addDataset("courses", readStream, InsightDatasetKind.Courses)
.then(function (res: InsightResponse) {
Log.writeResponse(res);
expect(res.code).to.equal(204);
}).catch(function (err: InsightResponse) {
Log.writeResponse(err);
Log.test("Should not have reached this point: " + JSON.stringify(err));
expect.fail();
});
});
Project structure: Testing
it("Test addDataset 204", function () {
let readStream = fs.readFileSync("$PATH_TO_ZIP_FILE").toString('base64');
return facade.addDataset("courses", readStream, InsightDatasetKind.Courses)
.then(function (res: InsightResponse) {
Log.writeResponse(res);
expect(res.code).to.equal(204);
}).catch(function (err: InsightResponse) {
Log.writeResponse(err);
Log.test("Should not have reached this point: " + JSON.stringify(err));
expect.fail();
});
});
base64 string represents the actual zip file
Project structure: Testing
it("Test addDataset 204", function () {
let readStream = fs.readFileSync("$PATH_TO_ZIP_FILE").toString('base64');
return facade.addDataset("courses", readStream, InsightDatasetKind.Courses)
.then(function (res: InsightResponse) {
Log.writeResponse(res);
expect(res.code).to.equal(204);
}).catch(function (err: InsightResponse) {
Log.writeResponse(err);
Log.test("Should not have reached this point: " + JSON.stringify(err));
expect.fail();
});
});
In this unit test we are testing the 204 case, you must test the other cases as well!
Project structure: Testing
it("Test async code", function () {
return facade.asyncFunction(...).then(function (res: InsightResponse) {
expect(res.code).to.equal(<CODE_NUMBER>);
}).catch(function (err: InsightResponse) {
expect.fail();
});
});
Every method from the API returns a promise, it means that every method from the API is an async method. Here's the default template for testing a async function:
Project structure: Testing
it("Test async code", function () {
return facade.asyncFunction(...).then(function (res: InsightResponse) {
expect(res.code).to.equal(<CODE_NUMBER>);
}).catch(function (err: InsightResponse) {
expect.fail();
});
});
More on JS promises and async programming next week
Every method from the API returns a promise, it means that every method from the API is an async method. Here's the default template for testing a async function:
Git and GitHub workflow
Your local repo/code
Your teammate's local repo/code
Your team GitHub repository
Code in version 0.0
Code in version 0.0
Code in version 0.0
Git and GitHub workflow
Your local repo/code
Your teammate's local repo/code
Your team GitHub repository
Code in version 0.1
Code in version 0.0
Code in version 0.0
You've changed the code!
Git and GitHub workflow
Your local repo/code
Your teammate's local repo/code
Your team GitHub repository
Code in version 0.1
Code in version 0.0
Code in version 0.0
git add <PATH_TO_MODIFIED_FILES>
git commit -m "New commit"
Git and GitHub workflow
Your local repo/code
Your teammate's local repo/code
Your team GitHub repository
Code in version 0.1
Code in version 0.1
Code in version 0.0
git push origin master
Git and GitHub workflow
Your local repo/code
Your teammate's local repo/code
Your team GitHub repository
Code in version 0.1
Code in version 0.1
Code in version 0.1
git pull origin master
Git and GitHub workflow: Branches
Git and GitHub workflow: Branches
git checkout -b branch_name
Creating and moving to a new local branch
Pushing the new local branch to GitHub
git add <path_to_modified_files>
git commit -m "Message"
git push origin branch_name
Git and GitHub workflow: Branches
git checkout -b branch_name
Creating and moving to a new local branch
Pushing the new local branch to GitHub
git add <path_to_modified_files>
git commit -m "Message"
git push origin branch_name
Merging to master branch
git checkout master
git merge branch_name
General tips and advice
Start early. Fail early.
Have enough time to fix things.
#1
#2
TDD and testing can help you break down the high level goals -- addDataset(), performQuery() -- into smaller, easily testable tasks: saveDatasetToDisk(), validateQuery().
Write these tests first, make sure they fail, then write the code to make them pass
Use TDD
Start early, please.
#3
#4 Write tests, mostly integration
Start early. I'm warning you.
#5
Avoid writing too many lines inside promises.then() or promises.catch(). This will save you some debugging time.
#6
#7
You: "I'm passing everything locally but failing when I call the bot"
Your code is wrong. Trust me.
#8
#9
When you're stuck:
- Get away from the computer
- Talk a walk
- Drink some coffee
- Get some sleep
- Go play some League (or whatever the cool kids are playing these days)
- Do not panic
#10
Keep communicating with your teammate, always. Communication is key.
Resources
Deliverable 1 tutorial
By Rodrigo Araújo
Deliverable 1 tutorial
- 2,770