I love building tools to help solve problems. I also love programming. Thanks to the Web, the tools I build can be made available to all. Even better, it’s easy to build a website that is the tool. No download required.
In this article I explore building a website from scratch considering UX, speed, mobile, SEO and AMP.
When I write in French, I often stumble on the conjugation of a verb. Unlike English, French has funky rules. Does it finish with an “s” or a “t”? There are some grammar rules that one forgets. For instance, the verb “finir” will end with an “s” or “t” at the present tense, but without in the past tense.
My natural instinct is to google “conjugaison finir” to find the correct grammar. There are tons of websites out there give you the answer. However they are bloated with ads. For example nouvelobs.com even ends up putting a big video ad which pushes the answer below the fold. How frustrating!
Of course, there are solutions to this. I could install a grammar checker. However I constantly switch between French and English. Checkers get confused with that all the time correcting the wrong language. I therefore avoid them.
Being in the browser, it’s pretty fast to open a new tab and google “conjugaison finir”. If only there was a clean, super fast and ad free website to give me the answer.
After living with this dilemma for a few years, I decided to create my own website with French verb conjugation. I also wanted to solve issues I saw with existing websites. These were the requirements I established for the site:
This article documents my journey of building conjugaison.xyz. I saw this as a good exercise in building a website from scratch.
Choosing a domain is always tricky. First and foremost, it is about branding and for it to be easy to remember. Ultimately I wanted my domain name to contain the keyword I would search for. In this case “conjugaison”. I would then add the verb name itself. Looking up the conjugation of the verb “finir” would yield this search query “conjugaison finir”.
Unfortunately conjugaison.com was already taken (or parked). So were logical variants laconjugaison.com or conjugaisonverbe.com. I had to get off the dot com domain.
During my research, GoDaddy suggested an alternative: conjugaison.xyz for only 2$ the first year. I liked the dot xyz extension. It had a nice ring to it and was easy to remember. And at 2$ it was a bargain.
What about SEO considerations? Samuel Lavoie points out that since 2012 Google does not give extra SEO points to sites that contain the keyword. In fact they penalize sites with exact domain match (EDM for short) if the content is poor. EDM is an interesting topic. Brian Harnish wrote a pretty enlightening guide about EDM. In short, Samuel believes there are 3 criteria that are used to identify a site of poor quality: hyphen in the domain name, an exact keyword match and a funky domain name. Too bad for me since conjugaison.xyz hits 2 out of those 3 criteria. Google may consider it of poor quality and lower it in rankings.
First and foremost this website is for me. So I won’t worry about that. If I one day decide to compete for French verb conjugation traffic, I will consider changing the domain name. For now however, conjugaison.xyz is real easy to remember for humans. When I talk to people about it, they easily recall it.
Most of these sites do more than conjugation. Things like word definition, word of the day, most commonly used words and so forth. In my case I didn’t care about that. My website would be there to do only one thing and to do it well — conjugation of a verb. With that in mind, I drew up this wire frame with the bare minimum.
The header has a link to the brand which also serves as a link to the home page; the list of all verbs. There is also a search box to quickly find a verb. Ultimately, I would like this search box to use Google search and drive to the correct page. But that’s a separate topic I will cover in the follow up article.
The content of the page contains the conjugation of the verb in question. That’s it. No sidebar, no ads, no verb of the day or links to other verbs.
Rarely does someone reach the footer. It is standard practice place to put the author (and copyright). That makes sense.
Bootstrap is pretty ubiquitous. I’ve been using it for many years now and it was the natural CSS framework for me to use. I decided to download only the bare essentials. Bootstrap 3 has a built-in Customizer tool to download what you want.
The final minified CSS file was 57kb and another 24kb for the theme. Ok, not too bad. Besides, the minified CSS file wouldn’t change. I could definitely push those assets to a CDN.
Here is the final design.
Speed should always be considered a feature. I strive to never compromise on speed. I believe that a website that takes long to load is a failure. Seems I’m not the only one. According to an Akamai and gomez.com study, abandonment rates increase dramatically for slow websites. Most users expect a site to load in less than 2 seconds. I’ll try to do it under 1 second.
When a developer thinks of a fast website, different technologies pop in their minds. There are back-end languages: Java, python, node JS, C#, ruby, PHP. There are databases: MySQL, MS SQL, Mondo DB. There are front-end libraries and frameworks: React, Angular, Vue, plain jQuery. There are bare metal servers, VPS (virtual private servers) and docker containers. Finally one also considers using a CDN (content delivery network) for serving static content like images, Javascript and CSS files.
For conjugaison.xyz — a purely static website — back-end technology is more a question of personal preference and knowledge. Either Java, Node JS or PHP would have done the job. I chose PHP because I already have experience building websites and applications using LAMP (Linux Apache MySQL PHP).
In March 2017 I switched from Rackspace to Amazon Lightsail. I’ve been very satisfied with the VPS quality and price. I have a 1GB of RAM server costing me a meere 10 USD a month on which I host all my personal projects. I chose a LAMP stack powered by Bitnami. Bitnami LAMP is Ubuntu pre-configured with Apache, MySQL and PHP. It also has PageSpeed to cache JS, CSS and image assets. It also includes popular PHP frameworks like Codeigniter, Laravel or Zend. Overall Bitnami LAMP is well documented and easy to use.
HTTPS is crucial nowadays and thanks to Let’s Encrypt, installing an SSL certificate is easy and completely free. Bitnami provides an excellent Let’s Encrypt how to guide.
On the front-end I decided not to use anything — no Javascript at all. That’s correct, you read that right. NO JAVASCRIPT. conjugaison.xyz consists of static web pages. I therefore decided to explore how far I could get not loading any Javascript at all.
At this point I considered whether I should generate static web pages or construct the pages on the fly using PHP.
My first attempt was to create one static page per verb and push those to a CDN. That’s 2000+ static web pages. As I experimented with building static pages, I hit the issue that any design change or any bug fix would require regenerating the 2000+ static pages and re-pushing them to the CDN. Updating 2000+ pages on the CDN does take time. Even with good CI (continuous integration) tools, there is no way to overcome the delay of updating those pages.
The static page solution seemed really archaic for two reasons. First, it would be very inefficient. It reminded me of the days when I used to FTP files to the server. Nowadays, performing a git pull on the server is much more efficient — only fetching changes.
Second, with static files I would lose the dynamism of building pages on the fly. I preferred this option much more than static pages.
You may assume that building pages on the fly is much slower than serving static web pages. Well the answer to that is yes and no as I show in the next section.
My second attempt was to use PHP to dynamically generate the HTML. My hypothesis here was that my server could render the HTML and send it fast enough. My target audience is geographically concentrated on the East Coast of North America, in the French speaking province of Québec. My Amazon Lightsail server is located in Ohio. I figured the website would load fast. Surely enough time to first byte (TTFB) was 40ms. That’s pretty fast. Overall from Montreal the HTML document came in under 200ms, sometimes much faster. My hypothesis was proven true.
Not having to worry about CDNs at this point gave me the biggest advantage of being able to hack real time on the prod website. Making a change to the website simply involved updating a PHP file on the server and voilà!
As a side note, nothing beats the dynamism and deployment speed of an interpreted language. In my case I simply use git as my CI. On the server, I run “git pull” and everything is up to date. Simplicity is bliss.
Of course if my server gets hit with thousands of requests per second, that’s another story. CDN provides the advantage of not hitting the server. I don’t think French verb conjugation is that popular. So I won’t worry about that.
Not having to download, parse, interpret and execute Javascript made the page even faster. We are so used to having Javascript loaded on pages nowadays. With React, Vue or Angular, there is no way around it. Fortunately, my website requires none of that. It’s just HTML. Something very satisfying going back to basics.
The only question I had was about the integrated search form.
<form class=”search” action=”/recherche” target=”_top”><input name=”term” type=”text” placeholder=”Trouver un verbe”value=”<?=isset($term) ? $term : ‘’?>” /></form>
Well as it turns out form submission is built-into HTML (I tend to forget that after years of using jQuery and Javascript librairies). Pressing enter just submits to the server. And since my pages are so light and load really fast, there is no need for client-side AJAX. When a search is performed, the browser appends query string ?term=miner
and loads the new page from the server. For example typing miner in the search box loads the page https://conjugaison.xyz/recherche?term=miner.
Searching involves two page loads. The first lists search results. The user then clicks on the wanted verb for a second page load. Could this be faster? Why not show the full conjugation of the closest matching verb below search results. I modified the website to do just that. Now you are guaranteed to have a verb conjugation following any search provided we find a match. In addition, the search term remains when you click on another matching verb.
In the back-end, the search page /recherche
simply does a redirection to the /verbe
page. In our particular case, this is the redirection:
Calling https://conjugaison.xyz/recherche?term=miner.
Reroutes to https://conjugaison.xyz/verbe/miner?term=miner.
I like this solution. It is like a mash of Google’s I’m feeling lucky with search results directly embedded on the page to avoid hitting back on the browser page. Very efficient.
A few years ago, Chrome introduced search directly in the browser address bar. I recall that day — it was an ah ha! moment. It eliminated an input box thus improving the user experience. At one point also, autocomplete was added to the address bar showing past searches and visited website addresses as you typed.
Recently, I discovered another cool thing about the address bar — integrated site search. Open a new browser tab and type “conjugaison.xyz”. Hit space and notice a vertical bar appears. Anything you type after will call the integrated search on my site.
Integrated browser search via Open Search
This is possible thanks to OpenSearch. OpenSearch “is a collection of technologies that allow publishing of search results in a format suitable for syndication and aggregation” (OpenSearch in Wikipedia). RSS and Atom feeds are part of that. So is integrated browser search.
In order to enable OpenSearch on your website, you need to create an OpenSearch description document; an XML files which tells search engines what URL to call to perform the search. Here is the opensearch.xml on my website.
<OpenSearchDescription xmlns=”http://a9.com/-/spec/opensearch/1.1/" xmlns:moz=”http://www.mozilla.org/2006/browser/search/"><ShortName>conjugaison.xyz</ShortName><Description>Conjugaison des verbes en français</Description><InputEncoding>UTF-8</InputEncoding><Image width=”16" height=”16"type=”image/x-icon”>https://conjugaison.xyz/favicon.ico</Image><Url type=”text/html” method=”get”template=”https://conjugaison.xyz/recherche?term={searchTerms}"></Url></OpenSearchDescription>
The Url
tag tells the browser to search with an HTTP GET
using the specified URL. It says the result will be an HTML document.
In addition to this, you must add a link meta
tag in your HTML document to inform the browsers and allow autodiscovery of your search plugin.
<link rel=”search” type=”application/opensearchdescription+xml” href=”/opensearch.xml”>
Bootstrap is responsive out of the box, therefore the website was already mobile. The one change necessary was preventing the navigation bar from collapsing on narrow screens. With a little CSS, I was able to obtain the following responsive results on iPad and iPhone 4. On a very narrow screen, the tag line is hidden in the navbar. The search box falls below the brand. I also shortened the title to ensure the important content is above the fold.
What about performance on mobile? I performed further testing using the Developer Tools’ Performance Audit. It measures the performance as it would be experienced on a typical mobile device and 3G connection (the code emulates mobile by throttling connection speed to 1.6Mbs, the average 3G connection speed).
Here is that audit:
With a 98/100 score and 2.100s time to interactive, it’s pretty good but twice my set goal of 1 second? Further analysis points to one thing slowing down the page: the custom font I am using. According to the audit, we lose 570ms loading and painting the Courgette font. I therefore ran an experiment removing the custom font. I reran the audit:
With a perfect score of 100 and 790ms time to interactive, that’s quite substantial! Not loading that custom font shaves off over 1,200ms — twice what the audit reported!
Hold on, let’s put some context around that…
First the Performance Audit emulates an average mobile device running on 3G. This excludes my target audience in Québec who have recent iPhones and LTE connections. Second, it measures the first load and doesn’t account for subsequent loads whereby assets are cached.
This point is important. The browser will cache the custom font. Although the first load may take 2 seconds, subsequent loads should take less than 1 second.
In the end I decided the custom font was important to the design of conjugaison.xyz. I therefore decided to keep Courgette sacrificing first load time.
SEO or search engine optimization is a big hairy beast. Usually it consists of two parts: on-site SEO vs off-site SEO. On-site SEO deals with making a website search-friendly. Thinks like sitemaps, robots.txt, structured data, meta tags (title, description), keywords and so on…
Off-site SEO is about link building — getting other websites pointing to yours in order to build authority, relevance and trust.
I won’t cover off-site SEO in this article. One day I may decide to compete for traffic however for the time being conjugaison.xyz is for me first and foremost.
Going back to my wishlist there remains one thing to look at: Google Search. I want to be able to google “conjugaison finir” and find my website rapidly. As I mentioned there are lots of established websites competing for the keyword “conjugaison”. Yet I know from experience that Google will consider a domain name as pretty unique. Therefore I can change my query to “conjugaison.xyz finir” and hopefully the correct page of my website would show up as a first result. Following are the on-site SEO relevant aspects I worked on in order to attain my objective.
Search engine bots crawl website pages looking for keywords. The Indexer then tries to determine what the site and pages are about. In my case it’s pretty damn simple — conjugation of a verb. Therefore each of the 2000+ pages I have follow this title pattern: “[verb] — Conjugaison du verbe [verb]”. In addition, I build the URL scheme in a logical fashion: conjugaison.xyz/verbe/[verbe].
It is best practice to build a sitemap.xml file which contains a list of your pages. For conjugaison.xyz, I wrote a PHP script to generate the sitemap.xml with the 2000+ pages. The sitemap.xml file sits at the root of my website.
Ever notice some websites have a search box directly integrated in the Google search result? It is something called Sitelinks Searchbox and rather easy to implement if your website already has a search engine. I needed only to provide the proper markup to tell Google Search:
<script type="application/ld+json">{"@context": "http://schema.org","@type": "WebSite","url": "https://conjugaison.xyz","potentialAction": {"@type": "SearchAction","target": "https://conjugaison.xyz/recherche?term={search_term_string}","query-input": "required name=search_term_string"}}</script>
Note that Google specifically states that the Sitelinks Searchbox markup should only appear on one page. In my case, it is the homepage — the index of all verbs contained on the site.
Google also provides a structured data testing tool to help you validate the markup.
In order to appear in Google, Google must know you exist. Google provides a tool called Google Search Console (formerly known as Google Webmaster Tools). You can add your web property, provide a sitemap and ask Google to index your website. Google Search Console will also assess your site, show you statistics, and provide you with hints to optimize your website and make it search engine friendly. To learn more, Kissmetrics has a good article covering Google Search.
I added conjugaison.xyz in Google Search Console, got Google to index the website and then tried a search in Google for “conjugaison.xyz”. The site appeared in the search results- yeah! I then tried to search for a verb: “conjugaison.xyz finir”. My website did not appear on any of the first pages of search results. Crap.
I then discovered that you can force Google to search only a site using this pattern: “site:conjugaison.xyz finir”. It is called site specific search. That search result gave me only one result — that of the home page listing all verbs. The conjugation page it seems was not in Google’s index.
At this point, let me tell you the most important thing about SEO. Its patience. You see Google will take time to crawl your site and add that to its search results. I waited 1, 2, 3 days and still nothing. The week after, only a few verbs appeared. Another week later the magic happened — Google was able to give me consistent results when I was searching for a verb in my website. Search query “site:conjugaison.xyz finir” finally gave me this:
Google even prioritized the verb page over the home page as first result. Bingo.
I am very satisfied with conjugaison.xyz as a personal tool to look verb conjugation in French. The website is fast and the user experience for verb lookup is very efficient in the browser, on Google Search and on the website itself. I think I reached my goal.
Even better is the killer feature I discovered — integrated browser search thanks to Open Search. To lookup a verb I simply have to open a new tab, type in “conjugaison.xyz” and space to enter search mode. As shown in the following video, it takes me 5 seconds to lookup a verb. The majority of that time is me typing and moving the mouse. The search and website load takes less than 1 second.
Special thanks to Daniel Tousignant-Brodeur, Pierre-Luc Maheu, Alexis Philippe and Samuel Lavoie for reading drafts and providing feedback.
If you enjoyed this story, may I suggest Fast and Free RAD Using GitHub Pages.