Image Image Image Image Image Image Image Image Image Image

Being Brunel |

Scroll to top

Top

No Comments

Building A Web App Part 4: Writing Code

Building A Web App Part 4: Writing Code

In the last, fairly epic, post of this mini-series I walked you through the stack we’re going to be using for this web application that will unite all you built environment professionals. What we haven’t got, yet, is something that will actually run; just a lot of tools, libraries and configuration. By the end of this post we’re going to have a static prototype. How’s that for fun?

Bootstrapping

Before we can start writing our functional code we need to provide an entry point. For a website, that’s an HTML page that the browser will download and render. If the site is actually a web application, then that HTML will point to a JavaScript file that will load in all the framework files, libraries and then actually start our app going. This is called bootstrapping.

From the configuration of our application, we said that when it started it should use webpack to compile our application starting with a few key files. Those were ./app/index.html and ./app/index.js. These two files are going to be our bootstrap, they’re going to provide a page that will start the browser loading the JavaScript (index.html), and then pull in the framework and libraries and actually start the web application (index.js).

The application code (i.e. the JavaScript) is going to handle actually rendering our application, so our landing/bootstrap HTML just wants to be as simple as possible:

This is a fairly minimal HTML page. It starts with the preamble about how the page is encoded, how it should be viewed on various devices, and the title that should be shown in the browser tab/window. The next section deals with some simple styling. First we pull in the Material Design font (called Roboto) from the GoogleFonts API. Then we use some inline CSS (a language for styling) to say that we want all our fonts to be slightly off black, in Roboto, and we want our headings (h1 and h2) to be light-weight (the opposite of bold). Finally we create a space for our application (<div id="content" />); this will be replaced by whatever the JavaScript renders once it has loaded.

You might notice that there is nothing in this HTML to actually load the scripts. This is because this file will be compiled through webpack and the links to the generated JavaScript will be injected at the end of the file (thanks to the HTMLWebpackPlugin section of our configuration). If we hadn’t of being doing it this way then we would have had to have added <script /> tags to the end of our body. However, if something can be automated easily- it probably should be.

Next up comes the JavaScript (./app/index.js):

This script will create the world’s least inspiring application- something that just shows the words “Hello World“. However all we’re doing at the moment is creating our entry point- the actual functionality is yet to come. In this file we’re importing the React framework, and the render function from the React DOM library (the DOM is a technical name for the system that lays out pages in a browser). We’re then defining our app as a paragraph element saying “Hello World” and then locating the section in index.html (the document that this script is called from) that has been labeled ‘content’ (which we’ll call the application’s root element- the place that it starts). Finally we’re using the render function to render our app into the root element.

Congratulations, we’re now bootstrapped. You can finally run npm start, browse to http://localhost:3000 and you’ll be shown the uninspiring words “Hello World.” Once you’re bored, press ctrl+c in your terminal to stop the server running.

Testing

Good tests are tests that are written before you write the functionality. This is because you’re specifying what the behaviour should be, not verifying that what you implemented did what you thought it should. The procedure most developers follow is this: write a failing test (because there’s no functionality), implement the functionality to the point the test passes, then refactor, tidy, and verify you haven’t broken the test. This is called the red, green, refactor system.

You’re going to have to bare with me now, because this next bit requires a bit of a leap of faith. We’re going to create test for our one behaviour we outlined (Given a list of interests, When a user selects interests, Then a list of appropriate channels should be shown.) To keep things organised we’re going to put our specifications in a separate folder, so in the file ./app/specs/channelFinder.spec.js we’ll write the following:

I know what you’re thinking: “how the hell did you come up with that?”. Let’s talk through it. Firstly, I’ve taken a punt at what my components are going to be called (I can always come back and change this test). I’ve said that this whole unit that collects interests and returns channel names is called a “channel finder”, that the list of channels will be a channelList, and that it each item in that list will be a ListItem, that construction will be an interest and it’ll only have one channel associated with it.

Knowing my assumptions, hopefully the test starts to become a bit clearer. It verifies that no channels are currently selected, finds an interest called construction and then clicks on it (called a tap, to be generic across desktops and phones). Finally, it verifies that, after tapping on an interest, the list of suggested channels now includes something. Possibly the most cryptic bit at the start is where we mount this app component with a store. That’ll be explained in the next post; for now you’ll just have to trust me that this is the line needed to create our application.

Just one thing I want to mention about this test, is that it is an intergration test; it tests how the application functions as a whole. It’s also very brittle, which is not ideal. Consider- this test will break if construction has more than one channel associated with it; which is not an indication that the behaviour of the application has changed. I’ve thrown together this test quickly because I’m just using it as a helpful way of telling “if I’m there yet” when I’m writing this prototype. As the program evolves, so will your tests- from development aides to ways of proving the system against accidental change.

We can now run our test using the npm test command we setup last time. As we have absolutely none of this implemented, your test will fail. Like the server, press ctrl+c to close the test suite. However, it’s not uncommon to leave it continuously testing, so that you get notified immediately once you’ve achieved your goal.

Components

So now we have a way of getting our application started, and verifying that we’ve delivered on our intentions, let’s take this a little further than “Hello World”. Different frameworks lead to different development styles. For React/Redux, it makes sense to create a static version of your website from the inside out, and then wire in the functionality. This is because it’s component based (to make a channel finder, you need a interest picker and a channel list first), and functional (in this case that means: the graphical interface is independent of the behaviour of the system).

We’re going to create two new directories: ./app/components and ./app/containers. In React/Redux terminology, a component is something that takes some inputs and renders something (sometimes called dumb components), while a container (also called a smart component) fetches data, interprets it and passes that down to the components. The idea is that components are not specific to the data you’re using; like the difference between a line and a drawing- a line can be used anywhere, but your drawing represents one thing only.

First, let’s create our component that will allow people to pick interets (./app/components/InterestPicker.js):

This file really showcases how React works. We create a component (interestPicker) that takes three parameters: a list of interests, a list of interests that the user has selected, and ‘a way’ of toggling if an interest is selected. It then returns a block to be rendered with a header inviting people to answer “What interests you?”, and a set of buttons (RaisedButton from Material UI). Each of those buttons is labeled with an interest, is set to be coloured (or primary in the language of Material Design) if said interest in in the list of selected interests, and is linked to a function (toggle) that will be called when it’s tapped.

Our Channel List (./app/component/ChannelList) is in a similar vain, but even simpler:

All the Channel List takes is a list of channels. It then outputs a block with a header (“You should checkout:”) and either a list of all the channels (with a nice icon) or a prompt (“Nothing yet. Please pick a few more interests.”) if there are no channels. If you take anything away from this; appreciate the simplicity of the React ‘data in – render out’; this is called a stateless component. Stateless components are ridiculously easy to read and test, as they mimic mathematical functions– you know that if you pass Channel List a list of three channels it’ll show them; there’s no setting up, no creating an object and then calling methods to move it into the right state, it’s just a simple map between inputs and outputs.

Wiring in a Static View

Technically we’ve hit a point where we have to implement a container. However it’s helpful practice to implement your container as a component first. That is, instead of worrying about writing the routines to fetch and interpret data- just create something that pass in some unchanging, sample, data. Aside from giving us a way to visually check the web app looks like we were expecting, it is also trivial to wire this in to the data when we promote it to being a proper container.

So let’s write our static version of ./app/containers/ChannelFinder.js:

The container code looks a lot like a standard component. We’re taking in all the data from our application (the interests, those that are selected, the channels suggested, and the function to toggle interest selections), and then passing them down the specific components that deal with each. The only difference is that we’re supplying the values to be rendered (in the defaultProps object) as well. In this case I’ve thrown a few interests together (although I’ve repeated them because making up data is boring), said that ‘eurocodes’ are selected, and put in a few channels. In the next post we’ll take this out and wire in a back end, but it’ll do for now.

Finally we’re going to connect this into the bootstrap. Material UI requires us to set a theming context- used to decide what colour, size, etc. every component included within it will be. It also needs us to load in the tap-event plugin before we start rendering. To make this process a bit tidier we’re going to split our bootstrap up. We’ll keep ./app/index.js as the process of creating the app component and rendering it into our root element on the page. But we’re going to move the definition of our app component into a separate file: ./app/App.js:

And updating our ./app/index.js:

This keeps our index.js clean from the ‘noise’ introduced by having to wrap our Channel Finder in the MuiThemeProvider elements used by Material UI to set the themeing. This separation will also be helpful in the next post where we’ll need to introduce some Redux elements too.

Once again our app is in a working state, and when we start the server (npm start) and browse to our site (http://localhost:3000) we’ll see a nice cloud of tags and a list of channels. Nothing will happen if we click on them (and if you’ve got npm test still running you’ll see that we haven’t passed our test yet), but it verifies that your interface is sound.


A clear idea of a minimum viable prototype, what we’re doing, what it’ll look like, how it’ll behave; a stack built and a working (but not interactive) interface- we’re doing pretty good. Although we’re on our fourth post now, it’s worth noting that once you’ve invested the time in learning- something like this will take you no more than afternoon. And once you’ve got a few stacks under your belt you’ll find you pick them up a lot quicker- as with music, there’s nothing original out there.

This post is part of a five post mini-series on building a web app: Part 1Part 2Part 3Part 4Part 5.

Submit a Comment

Leave a Reply