6 in 6 Challenge Week 2

Matt Ha
14 min readMar 23, 2015

-

Ask Five Whys

If you’ve ever had to answer a precocious child who wants to know “Why is the sky blue?” and keeps asking “Why?” after each answer, you’re already familiar with what we are going to build. This technique was developed as a systematic problem-solving tool by Taiichi Ohno, the father of the Toyota Production System.

Yes, you guessed it right, we’ll build a small app to help us easier find and understand roots of our problems in 30 minutes as a second part of Challenge to build 6 apps in 6 weeks in Meteor. You can find first part here.

Again, it will be rather easy to build and you can further extend it as you like. The Five Whys system takes its name from the investigative method of asking the question “Why?” five times to understand what has happened. In this app you can submit a problem and it will ask you five times why the problem is happening to help you better understand the real root cause of the problem.

The real cause of the problem is often hidden behind more obvious symptoms.

Before we begin, you can try out a live demo of the app here.

Github repo here.

Setting up Meteor

In order to this tutorial you’ve to have Meteor running on your machine. I really like that we could start with development just with one command in terminal installing Meteor. In my previous attempt to get around Python and Django, I spent two days only setting up the environment to start. We’ve already installed it in the part 1/6 so jump straight to 6 in 6 Challenge Week 1 — Yik Yak Web Clone to see installation process. Install Meteor and create your app — I named mine surprise surprise - week2.

I know that we just began, but let’s quickly talk about the structure of our application. I found an awesome post on How to structure your Meteor application and it’s good habit to make our application readable for others, for example if it gains traction and we want to further develop it. Since we are now in the app folder, type in terminal the following to create basic structure :

mkdir client server lib public stylesheet

Creating interface

Now that we have basic structure, let’s dive in the interface creation. I guess I’m allowed to talk more about the whole process, not just coding in Meteor here☺. I started drawing sketches on the paper on my way to school on Monday. This was the first sketch on how the site could look like :

Mom says I won national painting contest as a kid, but I don’t really believe her, now you know why. I wanted to see how site would look live and draw first wireframes in Photoshop. Here is the same one you just saw above :

And this is how the same site looks now :

You can play a little with it, to get a better idea of what we are about to build.

Let’s begin with main.html :

<head>
<title>Ask Five Whys</title>
<!-- To support mobile-devices -->
<meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
</head>
<body>
{{> problemsAll}}
</body>

We added user-scalable=no to the viewport apart from the part 1, what does make our app look more like an native mobile app on smartphone.

At first we need to create problems_all.html and type the following into it :

<template name="problemsAll">
<div class="main-heading-problems">
<h1>Problems</h1>
</div>
<div class="text-center">
{{#each problems}}
{{> problemItem}}
{{/each}}
</div>
</template>

And also problem_item.html :

<template name="problemItem">
<div class="problem-items">
<a href="/">
<li class="problems">
<h3>{{postProblem}}</h3>
</li>
</a>
</div>
</template>

We created problemItem template where we will store ‘problems’ from database and then iterate over those using {{#each}}.

We now need to create a collection of problems, to be able to store them in our database. In lib folder create problems.js and type :

Problems = new Meteor.Collection("problems");

The above code will store all our problems in the database. Doesn’t it sound great ? Since we’re weird and want to show our problems to everybody to see we create helpers.js in client and type the following :

Template.problemsAll.helpers({
problems: function() {
return Problems.find();
}
});

Navigate to the browser and type localhost:3000 . Now we see only the heading Problems. Let’s try to insert some problems into our app to let it care about them instead of us. Open JavaScript console (In Google Chrome Cmd + Alt + J) and type :

Problems.insert({postProblem : 'My problem'});Problems.insert({postProblem : 'My 2 problem'});Problems.insert({postProblem : 'My 3 problem'});

Now that we store three problems in the collection our app displays these on the screen. Let’s make our app look better by copying code from https://github.com/mhlavacka/Week-2/blob/master/stylesheet/style.css and inserting it to style.css in the stylesheet folder. Also add bootstrap from the terminal :

meteor add twbs:bootstrap

Now we should see something similar to this :

Submitting problems :

We are able to display our problems, but we don’t want to add them through the console in browser forever. Since the point of the site is to help us find the root of our problem through asking about them in dialog. Let’s get to work, we need to create submit_problem.html and submit_problem.js. Those two will be the biggest files we are about to create. We’ll start with the interface :

<template name="submitProblem"> <!-- don't allow to submit form only using enter -->
<form onkeypress="return event.keyCode != 13;" class="form text-center">
<div id="submit-problem">
<div class="main-heading">
<h1>ASK FIVE WHYS</h1>
</div>
<div class="part1 dent-main">
<input autofocus="autofocus" type="text" name="problem" id="problem" placeholder="What’s the problem ?"/>
<input type="button" id="route" value="Find Its Route" class="route btn btn-sample">
</div>
</div>
<div id="submit-why1" class="hidden">
<div class="main-heading">
<h1>WHY #1 ?</h1>
</div>
<div class="part2 dent">
<input autofocus="autofocus" type="text" name="why1" id="why1" placeholder="Because …"/>
<input type="button" value="Answer #1" class="btn-sample btn answer1">
<!-- Back button -->
<button type="button" class="btn back1 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>
<div id="submit-why2" class="hidden">
<div class="main-heading">
<h1>WHY #2 ?</h1>
</div>
<div class="part3 dent">
<input autofocus="autofocus" name="why2" id="why2" type="text" placeholder="Because …"/>
<input type="button" value="Answer #2" class="btn-sample btn answer2">
<!-- Back button -->
<button type="button" class="btn back2 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>
<div id="submit-why3" class="hidden">
<div class="main-heading">
<h1>WHY #3 ?</h1>
</div>
<div class="part4 dent">
<input autofocus="autofocus" type="text" id="why3" name="why3" placeholder="Because …”/>
<input type="button" value="Answer #3" class="btn-sample btn answer3">
<!-- Back button -->
<button type="button" class="btn back3 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>

<div id="submit-why4" class="hidden">
<div class="main-heading">
<h1>WHY #4 ?</h1>
</div>
<div class="part5 dent">
<input autofocus="autofocus" type="text" id="why4" name="why4" placeholder=”Because …”/>
<input type="button" value="Answer #4" class="btn-sample btn answer4">
<!-- Back button -->
<button type="button" class="btn back4 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>
<div id="submit-why5" class="hidden">
<div class="main-heading">
<h1>WHY #5 ?</h1>
</div>
<div class="part6 dent">
<input autofocus="autofocus" type="text" id="why5" name="why5" placeholder="Because …"/>
<input type="button" value="Answer #5" class="btn-sample btn answer5">
<!-- Back button -->
<button type=”button” class="btn back5 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>
<div id="submit-solution" class="hidden">
<div class="dent mobile-side part7">
<input autofocus="autofocus" type="text" name="solution" id="solution" placeholder="What could be the best solution ?"/>
<!-- Submit button -->
<input type="submit" id="submit-all" name="submit-all" value="Answer" class="btn btn-sample submit-all">
<!-- Back button -->
<button type="button" class="btn back6 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</div>
</form>

</template>

It looks complicated but it’s really only a HTML form. To display the form we’ll add Iron Router, the package build for Meteor, which enables routing in our application. Type the following in the terminal :

meteor add iron:router

Now we can set routes to our templates and no longer need to put templates in the body tag. Instead it we are going to use dynamic route called {{yield}}. Called templates are automatically inserted into it. Overwrite body tag with the following :

<template name='layout'>
<div class='containe'>
{{> yield}}
</div>
</tempalte>

We created our dynamic route, but we need to define it using Iron Router. We configure layout template as our interface structure so then we could route different templates into {{yield}}. Create router.js in the lib folder and type in it :

Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {name: 'submitProblem'});Router.route('/problems', {name: 'problemsAll'});

Now we see only the first form question in our browser. It’s because all the other questions are assigned to the class hidden, what makes them invisible for us. What we need to do is that when user clicks the button, it hides current question and shows her next one. We will do this using jQuery, I know, it might be done in more fancy Meteor way, but what do you do when you don’t know better.

The thing is that we assigned class hidden {display: none} to all questions except the first one, which we see. Every time when user clicks on the button we say to our app — add class hidden to the question I already answered and remove class hidden from the next question to let me see it. Also to be even more fancy we’ll add little JavaScript effect every time new question appears. We will use Magic Animations to do so. Copy the code from here, create a file magic.css in public folder and paste it in it. We store data that we want to be accessible on every device in public folder. Now we need to reference it into the <head> to make it work. Simply add in the <head> tag the following :

<link rel='stylesheet' href='/magic.css'>

Alright, now open up submit_problem.js and type both to show/hide elements and to make the magic effect work :

Template.submitProblem.events({
'click .route':function() {
if (problem.value != '') {
//magic effect
$('.part2').addClass('magictime swashIn');
//show/hide items with removeClass()/addClass()
$('#submit-problem').addClass('hidden');
$('#submit-why1').removeClass('hidden');
} else {
alert("You need to enter problem");
}
},
'click .answer1':function() {
if (why1.value != '') {
//magic effect
$('.part3').addClass(‘magictime swashIn');
//show/hide items with removeClass()/addClass()
$('#submit-why1').addClass('hidden');
$('#submit-why2').removeClass(‘hidden');
} else {
alert("You need to answer why is it problem");
}
},
'click .answer2':function() {
if (why2.value != '') {
$(‘.part4').addClass(‘magictime swashIn’);
//show/hide items with removeClass()/addClass()
$(‘#submit-why2').addClass(‘hidden’);
$(‘#submit-why3').removeClass(‘hidden’);
} else {
alert(“You need to answer why is it problem”);
}
},
'click .answer3':function() {
if (why3.value != '') {
$('.part5').addClass('magictime swashIn');
//show/hide items with removeClass()/addClass()
$('#submit-why3').addClass('hidden');
$('#submit-why4').removeClass('hidden');
} else {
alert("You need to answer why is it problem");
}
},
‘click .answer4':function() {
if (why4.value != ‘’) {
$(‘.part6').addClass(‘magictime swashIn’);
//show/hide items with removeClass()/addClass()
$(‘#submit-why4').addClass(‘hidden’);
$(‘#submit-why5').removeClass(‘hidden’);
} else {
alert(“You need to answer why is it problem”);
}
},
'click .answer5':function() {
if (why5.value != '') {
$('.part7').addClass('magictime swashIn');
//show/hide items with removeClass()/addClass()
$('#submit-why5').addClass('hidden');
$('#submit-solution’).removeClass('hidden');
} else {
alert("You need to answer why is it problem");
}
}
});

Everytime the button is clicked and input field isn’t empty do the magic trick, hide current element and show next one. Obviously, this can be done with less lines of codes with few functions, but come on it works so who cares. JK, I would love to see how you would solve it more efficiently.

Since the code for back button is similar to above, only reversed a bit, it’s your responsibility to make it work now. We still need to insert our inputs into collection and therefore we’ll create submit function inside events for submitted Problems :

'submit form':function(event) {
event.preventDefault();

var post = {
postProblem: $(event.target).find('[name=problem]').val(),
postWhy1: $(event.target).find('[name=why1]').val(),
postWhy2: $(event.target).find('[name=why2]').val(),
postWhy3: $(event.target).find('[name=why3]').val(),
postWhy4: $(event.target).find('[name=why4]').val(),
postWhy5: $(event.target).find('[name=why5]').val(),
postSolution:$(event.target).find('[name=solution]').val(),
submitted: new Date()
};

var solutionValue = event.target.solution.value;
if (solutionValue != '') {
Meteor.call('insertProblem', post, function(error,result) {
// Only when we don't get empty object
if(!error){
Router.go('problemPage', result);
}
});
}
}

We insert posts in the collection using server. We called the method insertProblem and now we have to define this method on server. Open up problems.js and type :

Meteor.methods({
insertProblem: function(post) {
var postId = Problems.insert(post);
return {
_id: postId
};
}
});

In this method we insert new post and return its <ID>. Why ? Because we want to route to it using its <ID>, when it’s successfully submitted. Let’s go to router.js and create a dynamic route in format /problems/:_id for it :

// redirect to the current submitted problem
Router.route('/problems/:_id', {
name: 'problemPage',
data: function() { return Problems.findOne(this.params._id); }
});

The last step is to create problemPage template to display our newly created problem :

<template name="problemPage">
<div class="cent-problem-page spaceing">
<div>
<li class="list-group-item">
<h3>Problem — {{postProblem}}</h3>
</li>
</div>
<div>
<li class="list-group-item">
<p>Why? — {{postWhy1}}</p>
<p>Why? — {{postWhy2}}</p>
<p>Why? — {{postWhy3}}</p>
<p>Why? — {{postWhy4}}</p>
<p>Why? — {{postWhy5}}</p>
</li>
</div>
<li class="list-group-item">
<h3>Solution — {{postSolution}}</h3>
</li>
<a href="{{pathFor 'problemsAll'}}"><input type="button" id="problem-page-back" name="problem-page-back" class="btn btn-sample" value="All problems"></a>
</div>
</template>

We display all the inserted values of the recently submitted post. Let’s now remove all previously inserted problems. Type in terminal :

meteor mongo

and when the database line opens :

db.problems.drop();

Now that we have clear database, try the whole process of inserting problem and answering questions, it’s supposed to look like the following :

Pretty neat, huh ? As you might know each new Meteor application contents package insecure, which allows us to interact with database using only client. It makes development easier in the beginning, but it’s not that helpful and safe when we put our app in the real world.

As Sebastian pointed out in the Meteor group on Facebook, Week 1 App wasn’t really safe at all, because everybody was able to interact with database from the console in their browser. Since our posts are added through the server, we can remove insecure package from terminal :

meteor remove insecure

Now when you try to insert, update or remove something from your console, it wouldn’t work. However it doesn’t mean that security is solved forever, but it’s good enough for our humble app right now.

Now let’s do something really cool with Meteor. When you answer questions, it’s kinda hard to remember previous answer. Since the whole process is based on it, we should be able to display previous answers to our users to make it more easier for them to answer. We could use Meteor reactivity to do this. Check this live example to get better idea what are we about to do. Now go to submit_problem.js and put the following just after our submit function :

'keyup input#problem':function(event) {
Session.set("problem", event.target.value);
},
'keyup input#why1':function(event) {
Session.set("why1", event.target.value);
},
'keyup input#why2':function(event) {
Session.set("why2", event.target.value);
},
'keyup input#why3':function(event) {
Session.set("why3", event.target.value);
},
'keyup input#why4':function(event) {
Session.set("why4", event.target.value);
},
'keyup input#why5':function(event) {
Session.set("why5", event.target.value);
}

As we said in the first tutorial, we use Sessions to store and access data on client, mainly for storing relevant data to current user. In our application we use Sessions to store values of the input fields in real-time. Everytime the user insert a letter in particular input, it’s stored in Session. Now we need to display the recently stored value. In helpers.js type :

Template.submitProblem.helpers({
problem: function() {
return Session.get(“problem");
},
why1: function() {
return Session.get("why1");
},
why2: function() {
return Session.get("why2");
},
why3: function() {
return Session.get("why3");
},
why4: function() {
return Session.get("why4");
},
why5: function() {
return Session.get("why5");
}
});

Now we get the value of inputs. One thing that still left is to display in interface of the submission process what we’ve just done. Open up submit_problem.html and edit as following :

<div id="submit-why1" class="hidden">
...
<div class="part2 dent">
<li class="list-group-item">
<p>Problem — {{problem}}</p>
</li>

<input autofocus="autofocus" value="{{why1}}" type="text" name="why1" id="why1" placeholder="Because …"/>
...
</div>
<div id="submit-why2" class="hidden">
...
<div class="part3 dent">
<li class="list-group-item">
<p>Why #1 — {{why1}}</p>
</li>

<input autofocus="autofocus" value="{{why2}}" name="why2" id="why2" type="text" placeholder="Because …"/>
...
</div>
<div id="submit-why3" class="hidden">
...
<div class="part4 dent">
<li class="list-group-item">
<p>Why #2 — {{why2}}</p>
</li>

<input autofocus="autofocus" value="{{why3}}" type="text" id="why3" name="why3" placeholder="Because …"/>
...
</div>
<div id="submit-why4" class="hidden">
...
<div class="part5 dent">
<li class="list-group-item">
<p>Why #3 — {{why3}}</p>
</li>
<input autofocus="autofocus" value="{{why4}}" type="text" id="why4" name="why4" placeholder="Because …"/>
...
</div>
<div id="submit-why5" class="hidden">
...
<div class="part6 dent">
<li class="list-group-item">
<p>Why #4 — {{why4}}</p>
</li>

<input autofocus="autofocus" value="{{why5}}" type="text" id="why5" name="why5" placeholder="Because …"/>
...
</div>
<div id="submit-solution" class="hidden">
...
<div class="text-left">
<li class="list-group-item">
<p>Problem — {{problem}}</p>
</li>
</div>
<li class=”list-group-item”>
<p>Why #1 — {{why1}}</p>
<p>Why #2 — {{why2}}</p>
<p>Why #3 — {{why3}}</p>
<p>Why #4 — {{why4}}</p>
<p>Why #5 — {{why5}}</p>
</li>

<input autofocus="autofocus" type="text" name="solution" id="solution" placeholder="What could be the best solution ?"/>
...
</div>

When you now go through the process of submitting your problem, it always shows you the previous answer.

We are almost finished, but there are two additional steps left just to make navigation in our application better. At first we need a way to link to clicked problems. Edit template in problem_item.html :

<template name="problemItem">
<div class="problem-items">
<a href="{{pathFor 'problemPage'}}">
<li class="problems">
<h3>{{postProblem}}</h3>
</li>
</a>
</div>
</template>

Also we need the way to submit new problem in problems_all.html :

<template name="problemsAll">
...
<div class="text-center">
<div class="button-align">
<a href="{{pathFor 'submitProblem'}}"><input type="button" id="submit-problem-page" name="submit-problem-page" class="btn btn-sample" value="Ask 5 why"></a>
</div>

<div>
{{#each problems}}
...
</template>

Now we are ready to deploy our small application for everyone to see. To deploy Meteor app, create name for your app and run the following in the terminal :

meteor deploy yourappname.meteor.com

Congrats ! We are live and also done for #2/6. It was really cool to see that I built this from idea only in 4 days (I was ill for other 2 days ). It’s only a second week but I already look forward to build something one step ahead part #2 in the #3 week. I know this app is not really that useful, but I wanted to have it in order to help me think deeper about problem solving and to question current state of how things work. As Paul Graham said :

If you’re looking for startup ideas you can sacrifice some of the efficiency of taking the status quo for granted and start to question things. Why is your inbox overflowing? Because you get a lot of email, or because it’s hard to get email out of your inbox? Why do you get so much email? What problems are people trying to solve by sending you email? Are there better ways to solve them? And why is it hard to get emails out of your inbox? Why do you keep emails around after you’ve read them? Is an inbox the optimal tool for that ?

Pay particular attention to things that chafe you. The advantage of taking the status quo for granted is not just that it makes life (locally) more efficient, but also that it makes life more tolerable. If you knew about all the things we’ll get in the next 50 years but don’t have yet, you’d find present day life pretty constraining, just as someone from the present would if they were sent back 50 years in a time machine.

When something annoys you, it could be because you’re living in the future.

I’m on twitter at @mhlavacka, if you want to see what I’m up to next.

--

--

Matt Ha

I build web projects 👨‍💻 For more frequent updates follow me on https://twitter.com/MattHlavacka