<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-10-28T00:37:18+00:00</updated><id>/feed.xml</id><title type="html">Antoine Leclair</title><entry><title type="html">Notes From Migrating Partially an App From Heroku To Disco</title><link href="/2025/07/28/notes-from-migrating-an-app-from-heroku-to-disco.html" rel="alternate" type="text/html" title="Notes From Migrating Partially an App From Heroku To Disco" /><published>2025-07-28T00:00:00+00:00</published><updated>2025-07-28T00:00:00+00:00</updated><id>/2025/07/28/notes-from-migrating-an-app-from-heroku-to-disco</id><content type="html" xml:base="/2025/07/28/notes-from-migrating-an-app-from-heroku-to-disco.html"><![CDATA[<p>This is more of a brain dump than a proper tutorial.</p>

<h2 id="why-a-partial-migration">Why a Partial Migration?</h2>

<p>I recently had to move parts of an app from Heroku to Disco. The app runs under an enterprise contract on Heroku, that allows for a fixed amount of resources. Dyno units as they call them. The usage increased temporarily due to a data migration that’s taking a few months, and Heroku checked in to see if the size of the contract should be increased.</p>

<p>Since the enterprise contract with Heroku still runs for another 6 months, I decided to move only a few workers to Disco, and leave the rest on Heroku for now.</p>

<h2 id="choosing-the-right-datacenter">Choosing the Right Datacenter</h2>

<p>Since the app is connected to a Postgres database and RabbitMQ, it makes sense to put the new Disco server in the same datacenter as the app running on Heroku.</p>

<p>You can find the region on Heroku using:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku info &lt;APPNAME&gt;
</code></pre></div></div>
<p>One of the fields is the region:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
Region:         us
...
</code></pre></div></div>
<p>You can then find that region in the list of regions:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku regions <span class="nt">--json</span>
</code></pre></div></div>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"country"</span><span class="p">:</span><span class="w"> </span><span class="s2">"United States"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2012-11-21T20:44:16Z"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"United States"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"59accabd-516d-4f0e-83e6-6e3757701145"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"locale"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Virginia"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"us"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"private_capable"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
  </span><span class="nl">"provider"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"amazon-web-services"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"region"</span><span class="p">:</span><span class="w"> </span><span class="s2">"us-east-1"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"updated_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2016-08-09T22:03:28Z"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>In this case, it’s AWS <code class="language-plaintext highlighter-rouge">us-east-1</code>.</p>

<h2 id="using-a-specific-dockerfile">Using A Specific Dockerfile</h2>

<p>The project already uses Docker for various purposes: Docker Compose for development, stagings run on Disco, the CI builds use Docker images. It was pretty easy to create a minimal <code class="language-plaintext highlighter-rouge">Dockerfile</code> that only installed the minimum for the workers I was moving to Disco. And then, since the project has many <code class="language-plaintext highlighter-rouge">Dockerfile</code> with different names, I just had to specify which one to use in <code class="language-plaintext highlighter-rouge">disco.json</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"services"</span><span class="p">:</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="nl">"worker_general"</span><span class="p">:</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"worker queues=default,rush"</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"worker_background"</span><span class="p">:</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"worker queues=background,rush"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"images"</span><span class="p">:</span><span class="w">
    </span><span class="p">{</span><span class="w">
        </span><span class="nl">"default"</span><span class="p">:</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"dockerfile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Dockerfile.prod.worker"</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="managing-multiple-discojson-configurations">Managing Multiple disco.json Configurations</h2>

<p>Similarly, since the project already runs staging environments on Disco, we already had a <code class="language-plaintext highlighter-rouge">disco.json</code> with a different list of services.</p>

<p>Disco let’s you specify another file by setting the environment variable <code class="language-plaintext highlighter-rouge">DISCO_JSON_PATH</code> to the name of the file to use instead. E.g.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>disco <span class="nb">env</span>:set <span class="se">\</span>
    <span class="nv">DISCO_JSON_PATH</span><span class="o">=</span><span class="s1">'disco.staging.json'</span> <span class="se">\</span>
    <span class="nt">--project</span> staging-one
</code></pre></div></div>

<h2 id="transferring-heroku-environment-variables">Transferring Heroku Environment Variables</h2>

<p>I exported the environment variables from Heroku using:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku config <span class="nt">--app</span> app-name
</code></pre></div></div>

<p>I removed a few magic Heroku variables, like <code class="language-plaintext highlighter-rouge">HEROKU_APP_NAME</code> and manually edited the output with VS Code multi-cursors to get a command like this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>disco <span class="nb">env</span>:set <span class="se">\</span>
    <span class="nv">VAR_ONE</span><span class="o">=</span><span class="s1">'value one'</span> <span class="se">\</span>
    <span class="nv">VAR_TWO</span><span class="o">=</span><span class="s1">'value two'</span> <span class="se">\</span>
    <span class="nv">VAR_THREE</span><span class="o">=</span><span class="s1">'value three'</span> <span class="se">\</span>
    <span class="nt">--project</span> prod-workers
</code></pre></div></div>

<h2 id="keeping-the-branch-clean">Keeping The Branch Clean</h2>

<p>When creating the project, I specified the branch I wanted to use (<code class="language-plaintext highlighter-rouge">production</code> in this case, but it could be <code class="language-plaintext highlighter-rouge">main</code> or <code class="language-plaintext highlighter-rouge">master</code>). But to avoid making the branch dirty by pushing (or force pushing) many small tweaks to get everything right, I pushed to antoher branch, and manually deployed using</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>disco deploy <span class="se">\</span>
    <span class="nt">--commit</span> 788ec8b1a1429f18cf28cf4937a54d9a57f9ae8a <span class="se">\</span>
    <span class="nt">--project</span> prod-workers
</code></pre></div></div>
<p>And when everything looked good, I squashed all the commits and merged to the correct branch (<code class="language-plaintext highlighter-rouge">production</code>).</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is more of a brain dump than a proper tutorial.]]></summary></entry><entry><title type="html">Building Things Properly</title><link href="/2016/02/22/building-things-properly.html" rel="alternate" type="text/html" title="Building Things Properly" /><published>2016-02-22T00:00:00+00:00</published><updated>2016-02-22T00:00:00+00:00</updated><id>/2016/02/22/building-things-properly</id><content type="html" xml:base="/2016/02/22/building-things-properly.html"><![CDATA[<p>As I’m working on <a href="http://grawl.it">Grawl</a> to push it to MVP, I thought I would
share some thoughts about building things properly.</p>

<h2 id="the-client-that-wanted-an-mvp">The Client That Wanted an MVP</h2>

<p>A few months ago, a prospect client asked for an estimate to build an MVP.
That MVP would have access to users bank accounts and be able to perform real
ACH transactions on their behalf.</p>

<p>The client wanted to build something extremely quickly to be able to prove the
market fit of his idea, which really does make sense. So I crafted an estimate
that would include the desired minimal feature set. He was surprised by the
amount of time needed to build that MVP (a few weeks).</p>

<p>For many reasons, I think he is a smart guy with a great business idea.
However, he had some misconceptions about what it means to build a web
application.</p>

<p>For a lot of people, the difference between a website and a web application can
be unclear, and that’s really understandable! I have to explain it from time
to time to clients, friends and family members.</p>

<p>So, that client asked for some explanation. Why would it take so much time to
develop his app?</p>

<h2 id="a-website-vs-an-application">A Website vs An Application</h2>

<p>First of all, let me explain some differences between a website and a web
application. You can use both through your web browser, like Chrome, Safari or
Internet Explorer, but conceptually, they are not the same.</p>

<h3 id="a-website-is">A Website Is…</h3>

<p>… content that you consume, that you read. Here are some examples:</p>

<ul>
  <li>A restaurant’s website where you can lookup the menu and the phone number.</li>
  <li>A furnitures factory’s website where you can see a list of what they make,
how to apply for a job, phone numbers of each departments, etc.</li>
  <li>A blog or a newspaper’s website, where you can read articles.</li>
</ul>

<h3 id="a-web-application-is">A Web Application Is…</h3>

<p>… software that you can use to do things. In most cases, you can log in.
Here are some examples:</p>

<ul>
  <li>A timesheet software where you can enter the time you worked at your day
job.</li>
  <li>A to-do application, where you add tasks that you have to
do, and check tasks that you have done.</li>
  <li>A bank’s web application where you can log in, see your latest transactions,
send money to someone, pay invoices.</li>
</ul>

<h3 id="the-line-is-blurry">The Line Is Blurry</h3>

<p>It’s not always super clear. Here are some examples where the line is blurry:</p>

<ul>
  <li>You can reserve a table at a restaurant using their website, this is handled
by software.</li>
  <li>Some administrator has to log into a content management system (CMS) to
add/edit/remove content from the furniture factory’s website.</li>
  <li>A user can log in the newspaper’s website and post comments to articles.</li>
  <li>The bank has a regular website, where it showcases it’s product. On the top
right corner of the page, it says that “You are logged in as Antoine
Leclair”, which has to come from the application.</li>
</ul>

<h2 id="developing-a-web-application-is-not-developing-a-website">Developing a Web Application Is Not Developing a Website</h2>

<p>The lifecycle of a website is not the same as the lifecycle of a web
application.</p>

<h3 id="the-lifecycle-of-a-website">The Lifecycle of a Website</h3>

<p>The lifecycle of the code base of a website is similar to a brochure. Some
process (meetings, design, production, etc.) leads to a final product. The
brochure is printed, ready to be read. The website is online ready to be read.</p>

<p>At some point in the future, it will get too old. A new one will be produced.
The same process starts over (meetings, design, production, etc.). The new one
is ready, the old one is discarded.</p>

<p>The code base of the website during his whole life will not change much. A new
social network appears, we must add an icon. The client did not realize he
needed a page that let people know how to get to the factory, a new page must
be added, with a new link to that page on  the home page. If the content has to
be changed (more articles in a blog, new products in the catalog), the code
base will rarely change. The changes will rather be done in the CMS without
touching the code base.</p>

<p>You rarely find bugs in a website because the code is simple: it gets data from
a database and shows it in a page, it affects how things are presented (the
color for example), it performs simple animations. If there are any bugs, they
are generally really simple to fix and deploy. Even someone unfamiliar with
the code base will be able to do it easily.</p>

<h3 id="the-lifecycle-of-a-web-application">The lifecycle of a Web Application</h3>

<p>The lifecycle of the code base of a web application is extremely different. It
really is a software dressed like a website.</p>

<p>You can rarely foresee every aspect of a software before actually using it.
There’s no solution, it’s like that. Software is intangible. Talking about it
without touching it only make things worse. So, the way successful software is
generally done is by delivering the minimal feature set that has value for the
users, and then augmenting/changing that feature set as time goes.</p>

<p>It is rarely a better idea to create a new version of a software and discard
the old one. For example, if you discover that your timesheet application would
also need to do some accounting and that users should have the ability to add
details about the hours worked, those features will be added to the existing
application, instead of creating a new application.</p>

<p>This requires a code base that is evolvable.</p>

<h2 id="some-considerations-when-building-a-web-application">Some Considerations When Building a Web Application</h2>

<h3 id="automated-testing">Automated Testing</h3>

<p>In order to make the code base elvolvable, the first thing that comes to my
mind is <em>automated testing</em>. There are many types of automated testing: unit
testing, functional testing, integration testing… I won’t go into the
details of each type. Some types of testing may be more appropriate than others
depending on the project.</p>

<p>An automated test is code that will reproduce a use case in an automated
manner and verify the result is correct. It could be code that tests that when
feeding <code class="language-plaintext highlighter-rouge">10</code> to the function <code class="language-plaintext highlighter-rouge">compute_taxes</code>, it actually returns <code class="language-plaintext highlighter-rouge">1.52</code>.
Or it could be remote controlling a real browser to simulate that a user logs
in, fills his daily timesheet then logs out, making sure that the changes were
saved correctly and the side effects (update a report, etc.) were done
properly.</p>

<p>To someone not familiar with writing software, it may seem like trivial test
examples that do not really add value. I’ll give you some examples where those
tests will come in handy.</p>

<ul>
  <li>
    <p>Three years after the software has initially been deployed, and the
person that wrote that code does not work there anymore, the business
expands and the function <code class="language-plaintext highlighter-rouge">compute_taxes</code> must be updated to compute the
taxes according to the state where the product is sold. Instead of receiving
only <code class="language-plaintext highlighter-rouge">10</code>, it will also receive <code class="language-plaintext highlighter-rouge">NY</code> or <code class="language-plaintext highlighter-rouge">CA</code>, and the function should return
the tax amount according to the state. You can update the existing tests to
include the state that was implied before (for example, <code class="language-plaintext highlighter-rouge">CA</code>), that make
sure the working case still works after the modification, then add new tests
to also test other states. The developer does not have to manually test each
cases. He just runs the tests, and that way, he is sure all the application
still works correctly.</p>
  </li>
  <li>
    <p>A bug report comes in. The taxes for <code class="language-plaintext highlighter-rouge">NY</code> are not computed correctly. If the
code base is not covered by tests, the developer will look at the code, fix
the bug, and test the application manually to see if the bug from the report
he received is now fixed. It seems to be fixed, so he pushes his change in
production. But by fixing the bug, he also introduced another subtle bug,
that made the tax calculation wrong for every other state. If the code base
is covered by test, the developer can run the test suite and catch the error
right away. Also, since there was a bug in the first place, the developer
will write a new test to make sure this bug never comes back.</p>
  </li>
  <li>
    <p>A new requirement is that the timesheet includes a new box to enter
the overtime, separated from the regular time. The existing browser test
should still work. It may look like a very simple change, but it’s often in
those unexpected cases that something breaks somewhere else. In this
example, loading the reports could make the application crash. The browser
test will find it really fast.</p>
  </li>
</ul>

<p>As most bugs are discovered as the code is being written, instead of receiving
bug reports, fixing them as they are introduced is much faster. Also, the test
suite is there to catch other bugs that the fix could introduce.</p>

<p>To summarize, automated testing really helps to keep a code base evolvable.</p>

<h3 id="pre-made-modules">Pre-made modules</h3>

<p>When building a website, pre-made modules/plugins are often useful. Need to
create an animated slideshow? There’s a jQuery plugin for that. Need a private
section on your website where only authenticated users can upload files?
There’s a WordPress plugin for that.</p>

<p>When building a web application, using those pre-made modules is often not the
optimal solution for many reasons.</p>

<ol>
  <li>While it’s normally accepted to adapt the requirements of a website
according to what the existing plugins can do, it’s normally not the case
for a web application. For example, it could be important that a user
provide his mobile phone number while signing up, but the existing modules
do not ask for that information.</li>
  <li>The requirements of a website will rarely change over time. If they change,
there are good chances that a new website will be built to replace the old
one. The requirements of an application do change. If a pre-made “users”
module was used, to allow users to authenticate and access a private area,
when the requirements change (they will), it could put you in a place where
you can’t modify the application to add the new behaviors. For example,
when first writing the application, we did not need to ask for the phone
number during signup, but two years later, we need that information to send
an SMS near the end of the signup process, but the module that was used
does not allow it.</li>
  <li>It’s often really hard to incorporate the pre-made modules into a complete
test suite. They generally lack the access points that would be needed to
test correctly, in the context of your application.</li>
  <li>Using pre-made modules is often more about hacking the module to make it
work in your context. Hacking code together to ship a website is perfectly
acceptable. Doing the same for an application will make very brittle code,
with really big consequences.</li>
</ol>

<p>When building a website, it makes sense to use those modules because it makes
it so much faster to ship! Not using it could mean 10x more time needed. Since
you don’t need to maintain that code, you would rather code 9 new websites over
time than investing time in the first one to make it really maintainable by
writing custom code. The first one will be thrown away in 2-4 years anyway.</p>

<p>When building a web application, you can’t afford to lose the
flexibility that pre-made module will take away from you. It could be
acceptable in some cases, but probably never in core parts of the application.
For example, if there is an animated slideshow in the application, it’s
probably OK to use that jQuery plugin. Replacing it with another one in the
future will be easy since there is nothing that really depends on it.</p>

<p>However, using pre-made “users” modules, or “administration area” modules, is
often a really bad idea when building software, because it will lock you in
using those modules forever, with their limitations.</p>

<h3 id="apis-and-mocking">APIs and Mocking</h3>

<p>When building websites, we sometimes have to access external APIs (data access
points that software can use). Most of the time, for a website, it is very
straightforward:</p>

<ul>
  <li>Fetching the latest tweets of a user and displaying them on a page.</li>
  <li>Getting the latest value of a stock and displaying it on a page.</li>
  <li>Getting the weather forecast of a city and displaying it on a page.</li>
</ul>

<p>You get the pattern: read data from one access point, output it on a page in
the desired format. Even better: there are often libraries or code examples
that do the data-fetching for you. Copy-paste and tada!</p>

<p>When building a web application, the consumption of those APIs are generally
not that straightforward.</p>

<ul>
  <li>There are often many calls to perform in a sequence.</li>
  <li>Data has to be saved in the database.</li>
  <li>That data in the database has to be architected to fit the exact business
needs of the current application. For example, if a user enters a credit
card (that is submitted to an external API), in your exact business needs,
that credit card could be associated to a group of users, even if in the
external API it’s associated to only one user.</li>
  <li>The API is only a data-access layer. It’s very easy to do one API call. But
it requires time to code all the meat around it. For example, if a user
entered a credit card to subscribe to your service, it would probably mean
that you have to keep track of the payments received for that user, and
keep the user account active as long as the payments allow it. That means
doing something special when the account becomes inactive. Also, what do
we do when that card has expired? What do we do when a payment fails?</li>
  <li>Since we are generally also sending data, there are generally error cases
that have to be handled. The user entered a wrong credit card number, we
have to tell the user that something failed.</li>
  <li>External APIs will also want to tell your application about events that
happen. You will have to write code that listen to those events and do
something about them. For example, a user subscribed to your services using
his credit card. You’ll have to listen for successful payments to increase
the duration of the subscription of the user.</li>
  <li>A call to an API could fail because the external provider is down, or there
is a network problem. You generally have to handle it in more complicated
ways than “just hide the tweets if you can’t read them”, as you would do on
a website.</li>
</ul>

<p>Also, since those APIs are external services, it can be hard or impossible to
write automated test suites (see above) that incorporates them. There are few
reasons for that:</p>

<ol>
  <li>Every time you begin each of the automated tests, you have to be able to
reset the environment to some initial known state. For example, if you had
a test where a user logged in, added time to his timesheet, then looked at
the updated report, you have to be able to reset the hours to some initial
state before the test. Otherwise, every time you run the test, one more
entry would be added, and the updated report would be unusable for testing
because you will not be able to make sure that the last x hours have been
entered, because they are already there 240 times from the previous runs of
the tests. You need to be able to reset the state. External APIs often do
not have that ability. They sometime only offer a sandbox where you can’t
reset the state to an initial condition.</li>
  <li>Some API providers don’t even offer a sandbox. It means all the calls that
your application will do, even during testing, will be made against the
live systems. It’s impractical for some, if not most, testing. For
example, you would have to submit a real credit card number and do real
transactions on it. Every time you run the tests. Which is many times a
day.</li>
  <li>The external API sandboxes are extremely unreliable. They are often
offline, the provider closes your sandbox account or changes your settings
without telling you, they are testing new features that breaks the old
ones, etc.</li>
</ol>

<p>Since you can’t include them in your tests directly, you have to create
something that behaves like them for the context of the test cases. It’s called
a “mock”. During the tests, your application will talk with that mock instead
of talking with the real API endpoint. It’s a mini-version of the external
service. For example, if you mocked a payment provider, it could accept all
credit card numbers except for one, that will be used for testing when the user
enters an invalid number. The payments could always work for all credit cards
but one number, where the payments always fail. Or it could refuse payments
of 29.99 on one specific card number. Or it could only allow for 2 payments of
29.99 on one specific credit card number, then bounce the next ones.</p>

<p>Since you wrote that mock and you host it, you have complete control over it:</p>

<ul>
  <li>It will always be online when you need it.</li>
  <li>You can reset it when you want.</li>
  <li>The reset you apply brings the state to the exact case that you need.</li>
  <li>You can simulate specific use cases e.g. two payments that works,
then a third one that fails, etc.).</li>
</ul>

<p>Those mocks are really needed and are really useful, but they also take time to
write.</p>

<h3 id="deployment">Deployment</h3>

<p>Deploying a website is generally done by uploading the new files to the server
that hosts those files. The developer sees that it looks good on when he worked
on it on his laptop, then he uploads it. Or even faster, some directly edit the
files on the production server.</p>

<p>Deploying a web application is generally more involving. You push your work in
a source code repository (think GitHub), a continuous integration (CI) server
builds the source (more on that below), runs all the tests, and allows you to
deploy if all the tests are green. Doing the setup of the CI server (how it
pulls the code from the repository, how it builds, how it runs the tests, how
it deploys) requires some time.</p>

<p>Also, there’s often a staging server to maintain, where a copy of the
application is running fake accounts. That way, you can demo new changes for
approval without deploying to the production server.</p>

<p>You must use those good practices when developing an application because
otherwise, bugs that did not occur on the developer’s laptop emerge in
production. The exact source of the bugs is always a surprise, but it includes:</p>

<ul>
  <li>The timezone was not the same on the developer laptop and on the production
server.</li>
  <li>The developer runs Mac OS X or Ubuntu, but the production server runs
another operating system, like Debian.</li>
  <li>The developer has a library installed on his laptop, but it’s not installed
on the production server. This allowed the developer to scale an image on
his laptop, but doing the same thing on the production server crashes.</li>
</ul>

<h3 id="database-migrations">Database Migrations</h3>

<p>When a website has been deployed, it rarely happens that the database schema
will change. For example, it will rarely happen that, suddenly, you need
captions in the pictures of the slideshow, while you did not need it when the
website was first published. Also, when that happens, you can connect to the
database, write the command that adds the new column, and execute it.</p>

<p>For an application, a change to the database schema is everyday life. But,
unlike the website, you can’t just connect to the database and write some
commands. It needs to be executed in a reproducible manner. Some reasons are:</p>

<ul>
  <li>More than one person may work on a project. Everyone has to keep their
schema up-to-date.</li>
  <li>There are more than one server to apply the changes: production, staging,
etc.</li>
  <li>The changes has to be tested before they are executed in production. Some
changes may fail or have unwanted behaviors. This has to be correct
the first time it runs in production.</li>
  <li>Many different features may be developed at the same time in parallel. The
database schema has to match the current branch of the code. In order to do
that, you have to apply changes and also be able to apply the reverse of
those changes easily when you change branch.</li>
</ul>

<p>This is why we need database migrations: a system to do database schema changes
in a reproducible manner. The simplest form could be a folder containing SQL
files. But it’s generally in the form of code that apply those migrations for
you when you ask for it.</p>

<p>Doing the setup of the migration system and writing proper migrations is
another task that requires time and is not needed when building a website.</p>

<h3 id="compiled-and-minified-resources">Compiled and Minified Resources</h3>

<p>When building a website, you may want to minify your resources. That means that
you take your JavaScript and CSS (style sheets) and use a minifier that will
reduce the size of those files by using many strategies, like change long
variable names like <code class="language-plaintext highlighter-rouge">numberOfChildren</code> to <code class="language-plaintext highlighter-rouge">b</code> and removing line breaks. Also,
there are new languages that developers sometimes prefer to use instead of
JavaScript and CSS, that will be compiled by a compiler to become JavaScript
and CSS. CoffeeScript and SASS are two examples. When you build a website,
building those resources is something that could be done manually. For example,
just before you deploy, you minify all your resources by using the command
line.</p>

<p>When building a web application, that process has to be automated. Some reasons
are:</p>

<ul>
  <li>You do not simply copy your code to the server when you want to deploy
(see deployment above). Some other server will deploy for you.</li>
  <li>The code is kept under source control. When the code is compiled and
minified, it’s generally on one single line, which means that the whole file
that contains all of your JavaScript changes every time you change one
single character in one of your file. This result if huge changes in every
commit, which makes the repository bigger (takes longer to clone) and harder
to understand.</li>
  <li>The minified version also needs to be tested by the CI server.</li>
  <li>The version deployed has to be the one tested on the CI server.</li>
  <li>The code changes a lot. Building the minified files manually every time
would not make sense.</li>
</ul>

<p>Doing the setup of the automated minification/compiling is something that also
requires time and could be skipped when building a website.</p>

<h2 id="the-discardable-prototype-to-test-market-fit">The Discardable Prototype To Test Market Fit</h2>

<p>Until now, I talked about a website vs a web application. I used the website
comparison, but it could probably also be valid with a prototype application
that you only want to use to discover if your idea has a market fit.</p>

<p>If you intend to throw away your prototype application right after you
discovered if your idea has, or not, a market fit, you could consider
prototype applications to have the same characteristics that a website would
have. In theory that is true. You will never need to maintain the code, so you
don’t have to bother about making it evolvable.</p>

<p>However, there are some more considerations before you can go that path.</p>

<p>First, it’s really easy to fall in the trap of thinking that you will discard
your prototype application really soon. In practice, the code base rarely gets
thrown away. A total rewrite is extremely rare. The shortcut you take now will
stay with you for a really long time. It will cost you money and agility.</p>

<p>Second, it’s not always possible to do a quick prototype like that. I’m going
back to the example I started with: the client wanted an application that would
have access to users’ bank accounts, see transaction history and other data and
perform ACH transactions. This is a case where the application will store
really sensitive data and would be able to perform really sensible operations.
A bug or a security breach would be a disaster for the users, the client,
the developer and everyone in between. In those cases, you have to write
reliable software. That means using the best practices mentioned above, like
automated testing.</p>

<h2 id="back-to-grawl">Back to Grawl</h2>

<p>Like I was saying in the introduction, I’m currently pushing
<a href="http://grawl.it">Grawl</a> to bring it to an MVP level. In this case, I’m my own
client. I would really like it to get there faster.</p>

<p>I’m currently writing the code that handles the credit cards. It seems quite
simple at first, but a lot of use cases have to be covered by the automated
tests. Otherwise, I could be charging too much to someone, leak private data,
allow someone to use the application without paying the correct amount, etc.</p>

<p>It takes time.</p>

<p>But building that part properly is <strong>required</strong>. That’s not an optional
feature.</p>

<h2 id="in-summary">In Summary</h2>

<p>This was a super long article, but I think writing a shorter one would not have
covered enough to be taken seriously.</p>

<p>Building software the right way requires time, but everyone wins in the end.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[As I’m working on Grawl to push it to MVP, I thought I would share some thoughts about building things properly.]]></summary></entry><entry><title type="html">The Importance of Idempotence</title><link href="/2014/08/11/the-importance-of-idempotence.html" rel="alternate" type="text/html" title="The Importance of Idempotence" /><published>2014-08-11T00:00:00+00:00</published><updated>2014-08-11T00:00:00+00:00</updated><id>/2014/08/11/the-importance-of-idempotence</id><content type="html" xml:base="/2014/08/11/the-importance-of-idempotence.html"><![CDATA[<p><em>tl;dr Idempotence helps create more robust systems.</em></p>

<p>Idempotence is a mathematical concept that should be understood by all developers.</p>

<p>An operation is considered idempotent when doing it more than once is the same as doing it once.</p>

<p>For example, multiplying by 1 is idempotent.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x * 1 == x * 1 * 1
</code></pre></div></div>

<p>Multiplying by 0 is also idempotent.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x * 0 == x * 0 * 0
</code></pre></div></div>

<p>The key concept to remember is that applying the operation once can have side effects, but applying it more than once will not do anything more that what was already done the first time.</p>

<p>Assignment is idempotent.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x := 4
</code></pre></div></div>

<p>You can assign 4 to x as much as you want, x will still be 4. But assigning 4 to x one time is different than zero time.</p>

<h2 id="http-verbs">HTTP Verbs</h2>

<p>HTTP verbs can be classified as idempotent or not.</p>

<p><code class="language-plaintext highlighter-rouge">DELETE</code> is an idempotent verb. No matter how many times you do it after the first time, it will give the same result as the first time. For example, <code class="language-plaintext highlighter-rouge">DELETE /users/4/contacts/3</code> could remove your contact with the ID 3. If you call it again, that contact has already been removed and nothing more should happen.</p>

<p><code class="language-plaintext highlighter-rouge">GET</code> is also idempotent. In fact, it’s more than idempotent. It is considered a safe method. Safe methods can be compared to multiplying by 1. Doing it zero, once or more times should have the same effect. All <code class="language-plaintext highlighter-rouge">GET</code> does is get a resource. For example, you should never use normal links to delete resources.</p>

<p><code class="language-plaintext highlighter-rouge">POST</code> is <strong>not</strong> idempotent. Every time you do it, you can expect a side effect to happen. For example, every time you <code class="language-plaintext highlighter-rouge">POST</code> a contact form, an email is sent.</p>

<p>When it comes to APIs, that concept is well understood by consumers and providers. Designing around it will result in <a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment">least astonishment</a>.</p>

<p>See Wikipedia: <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods">Safe Methods</a> and <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications">Idempotent methods</a>.</p>

<h2 id="message-queues">Message Queues</h2>

<p>Let’s say you build a web app to manage events. You can add people to the invitees of an event. In other words, an event has many invitees. For quicker response time, you decided to send all emails from a worker. So when a user finalizes an event, a message is queued. A worker gets that message and sends the invite emails for that event.</p>

<p>This is a really common pattern, and if you are not doing it that way, you should really start to.</p>

<p>You realize that you had an SMTP problem and all your emails have not been sent for some time, and it’s not even showing up in the logs! You think “oh, well, I’ll just call the function to send the emails again”, but you don’t know for which events you should call that function.</p>

<p>Here comes idempotence.</p>

<h3 id="when-you-execute-a-task-in-a-worker-always-make-sure-its-idempotent">When you execute a task in a worker, always make sure it’s idempotent</h3>

<p>For the email example, every time you send an email to an invitee, you can keep the datetime in the database, in the event invitee row. If it has already been sent (sent datetime is not NULL), don’t send it again. As easy as that. Also, you might want to check if the event is finalized. If not finalized, do nothing.</p>

<p>More generally:</p>

<ul>
  <li>Check that your job is ready to be executed (e.g. event finalized). If not, do nothing.</li>
  <li>Check that the job has not already been done. If done, do nothing.</li>
  <li>Do job, keep datetime or something else in the database, log that it has been done (e.g. “INFO Invitation email for event 234 has been sent to john.doe@example.com”).</li>
  <li>Keep jobs granular. You have 5 emails to send? Queue a job (e.g. <code class="language-plaintext highlighter-rouge">send_event_emails(event_id)</code>) that will queue the 5 other jobs (e.g. <code class="language-plaintext highlighter-rouge">send_event_email_to_invitee(event_id, invitee_id)</code>).</li>
</ul>

<p>You realize something went wrong? You can always call your function to send emails on all events. Still crashed when half of the emails were sent? Fix what was wrong and just call it again. Also, it’s easy to inspect what emails have not been sent yet. Bonus, you can do some intelligence with the datetimes (how many emails a day do we send? what are the peak hours?).</p>

<p>Also, some message queues don’t garantee that a message will be delivered only once. Amazon SQS is that way. Your workers should really only do idempotent tasks.</p>

<h2 id="sql-migrations">SQL Migrations</h2>

<p>In the same spirit as the worker example above, when you do an SQL migration, do it in an idempotent way when possible.</p>

<p>For example, you decide to split the user table in two tables. One for basic informations (<code class="language-plaintext highlighter-rouge">users</code>) and one for all details that are not always important (<code class="language-plaintext highlighter-rouge">profiles</code>). You put a foreign key <code class="language-plaintext highlighter-rouge">user_id</code> in the <code class="language-plaintext highlighter-rouge">profiles</code> table. You have a migration that takes every row in <code class="language-plaintext highlighter-rouge">users</code> (<code class="language-plaintext highlighter-rouge">SELECT * FROM users</code>) and inserts a row in <code class="language-plaintext highlighter-rouge">profiles</code> with user data. You run it, and well, it crashes midway after 1 hour, because of some NULL value you didn’t think about. You fix it and run it again, but you then realize that some users have already been processed and have two profiles.</p>

<p>The idempotent solution: instead of <code class="language-plaintext highlighter-rouge">SELECT * FROM users</code>, you can just select the users that don’t have a profile row. That way you can run it as many times as you want. It will only process the few users that have not been processed yet. A big advantage of that method is that you can leave your app running in production while you do the migrations. When you are ready to deploy the new code that uses the <code class="language-plaintext highlighter-rouge">profiles</code> table, you can call your function again to make sure the latest users that signed up are also migrated. That example is not so great, because a user could change some information in the <code class="language-plaintext highlighter-rouge">users</code> table during the migration, but I guess you get the point.</p>

<h2 id="denormalized-data">Denormalized Data</h2>

<p>You have an application where each user has many documents. They can search their documents by tags. Tags come from many sources. The title of the documents, the folders, actual tags, the names of the authors, etc. You decided to keep a table named <code class="language-plaintext highlighter-rouge">tags</code> where you keep all the tags for every documents, it looks like this: <code class="language-plaintext highlighter-rouge">id</code> (hash), <code class="language-plaintext highlighter-rouge">tag</code> (actual text of the tag), <code class="language-plaintext highlighter-rouge">document_id</code> (foreign key to the document). When you add an author to a document, it does an insert in the <code class="language-plaintext highlighter-rouge">tags</code> table. When you remove an author, it finds the good tag and removes it.</p>

<p>Someday, you see in the log there was an error every once in a while when inserting a tag because of an obscure character encoding issue. You fix the issue and deploy the new code. However, there are a lot of missing tags and you have no easy way to fix it manually.</p>

<p>Instead of just having functions of the type <code class="language-plaintext highlighter-rouge">add_tag_for_new_author</code>, you should have a function of the type <code class="language-plaintext highlighter-rouge">update_tags_for_document</code>. When you call that function, instead of just adding a tag for the author that was just added, it checks all the document, rebuilds the tags list and makes sure that the correct data is in the database. That way, the <code class="language-plaintext highlighter-rouge">tags</code> table is really managed as it should be: a cache. You could delete all rows from that table and just call <code class="language-plaintext highlighter-rouge">update_tags_for_document</code> on every documents. It takes 2s to update the tags for a document? Let the worker do it, queue a message.</p>

<h2 id="conclusion">Conclusion</h2>

<p>If you were not aware of idempotence, I hope I convinced you to use it. Also, please note that I kept the examples simplistic for educational purpose.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[tl;dr Idempotence helps create more robust systems.]]></summary></entry><entry><title type="html">Understanding Quadratic Bézier Curves</title><link href="/2011/08/27/understanding-quadratic-bezier-curves.html" rel="alternate" type="text/html" title="Understanding Quadratic Bézier Curves" /><published>2011-08-27T00:00:00+00:00</published><updated>2011-08-27T00:00:00+00:00</updated><id>/2011/08/27/understanding-quadratic-bezier-curves</id><content type="html" xml:base="/2011/08/27/understanding-quadratic-bezier-curves.html"><![CDATA[<p>In a client project I had to draw by hand a quadratic Bézier curve, because the
html5 canvas quadraticCurveTo does not return the information about the path
drawn and I needed it.</p>

<p>Some basic explanation of a quadratic Bézier curve. You have a
start point <code class="language-plaintext highlighter-rouge">P1</code>, an end point <code class="language-plaintext highlighter-rouge">P2</code> and a control point <code class="language-plaintext highlighter-rouge">C</code>. Both the <code class="language-plaintext highlighter-rouge">x</code> and
<code class="language-plaintext highlighter-rouge">y</code> of each point on the path is dependant on <code class="language-plaintext highlighter-rouge">t</code>, which will vary from
0 to 1. <code class="language-plaintext highlighter-rouge">t=0</code> at the begining of the curve and <code class="language-plaintext highlighter-rouge">t=1</code> and the end of the curve.</p>

<p>You draw an imaginary line between <code class="language-plaintext highlighter-rouge">P1</code> and <code class="language-plaintext highlighter-rouge">C</code> (<code class="language-plaintext highlighter-rouge">P1C</code> line) and
another one between <code class="language-plaintext highlighter-rouge">C</code> and <code class="language-plaintext highlighter-rouge">P2</code> (<code class="language-plaintext highlighter-rouge">CP2</code> line). For each value of <code class="language-plaintext highlighter-rouge">t</code>, you mark
an imaginary point on <code class="language-plaintext highlighter-rouge">P1C</code> and <code class="language-plaintext highlighter-rouge">CP2</code>. The point on <code class="language-plaintext highlighter-rouge">P1C</code> is at <code class="language-plaintext highlighter-rouge">t</code> of the line,
starting at <code class="language-plaintext highlighter-rouge">P1</code>, and the point on the <code class="language-plaintext highlighter-rouge">CP2</code> line is at <code class="language-plaintext highlighter-rouge">t</code> of the line,
starting at <code class="language-plaintext highlighter-rouge">C</code>. Let’s call those points <code class="language-plaintext highlighter-rouge">C1</code> and <code class="language-plaintext highlighter-rouge">C2</code>.</p>

<p>Then, you draw an imaginary line between <code class="language-plaintext highlighter-rouge">C1</code> and <code class="language-plaintext highlighter-rouge">C2</code>, and you mark a real
point at <code class="language-plaintext highlighter-rouge">t</code> of the <code class="language-plaintext highlighter-rouge">C1C2</code> line.</p>

<p>You repeat the procedure for every value of <code class="language-plaintext highlighter-rouge">t</code>, where <code class="language-plaintext highlighter-rouge">t</code> varies from 0 to 1.
All the points you marked on the line <code class="language-plaintext highlighter-rouge">C1C2</code> are showing the quadratic Bézier
curve.</p>

<p>Here’s a little animation I made to explain it better:</p>

<div id="bezier-example-1" style="position:relative;">
    <canvas class="curve" style="position:absolute;top:0;left:0;z-index:4;"></canvas>
    <canvas class="animation" style="position:absolute;top:0;left:0;z-index:3;"></canvas>
    <canvas class="points" style="position:absolute;top:0;left:0;z-index:2;"></canvas>
    <canvas class="grid" style="position:absolute;top:0;left:0;z-index:1;"></canvas>
</div>

<p id="bezier-example-1-t">t = <span>0</span></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.0.6/modernizr.min.js"></script>

<script type="text/javascript">
    $(function() {
        
        var CANVAS_WIDTH = 301;
        var CANVAS_HEIGHT = 301;
        var p1x = 20;
        var p1y = 200;
        var cx = 140;
        var cy = 20;
        var p2x = 280;
        var p2y = 280;
        if (Modernizr.canvas) {
            var $t = $('#bezier-example-1-t span');
            $('#bezier-example-1').css({
                width: CANVAS_WIDTH + 'px',
                height: CANVAS_HEIGHT + 'px'
            });
            var gridCanvas = $('#bezier-example-1 .grid').get(0);
            var gridContext = gridCanvas.getContext('2d');
            gridCanvas.width = CANVAS_WIDTH;
            gridCanvas.height = CANVAS_HEIGHT;
            
            var pointsCanvas = $('#bezier-example-1 .points').get(0);
            var pointsContext = pointsCanvas.getContext('2d');
            pointsCanvas.width = CANVAS_WIDTH;
            pointsCanvas.height = CANVAS_HEIGHT;
            
            var animationCanvas = $('#bezier-example-1 .animation').get(0);
            var animationContext = animationCanvas.getContext('2d');
            animationCanvas.width = CANVAS_WIDTH;
            animationCanvas.height = CANVAS_HEIGHT;
            
            var curveCanvas = $('#bezier-example-1 .curve').get(0);
            var curveContext = curveCanvas.getContext('2d');
            curveCanvas.width = CANVAS_WIDTH;
            curveCanvas.height = CANVAS_HEIGHT;
            curveContext.strokeStyle = "#777";
            curveContext.lineWidth = 2;
            curveContext.beginPath();
            curveContext.moveTo(p1x, p1y);
            curveContext.stroke();
            
            drawGrid();
            drawSetup();
            setInterval(updateDemo, 1000/30);
        } else {
            $('#bezier-example-1').html('Your browser does not support Canvas.');
            $('#bezier-example-1-t').remove();
        }
        var t = 0;
        var d = 1; // direction
        
        function updateDemo() {
            if (t > 1 || t < 0) {
                d *= -1; // change direction
                curveContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
                curveContext.beginPath();
            }
            t += 0.01 * d; // continue moving
            $t.html(Math.round(t*100)/100);
            // update values
            var c1x = p1x + (cx - p1x) * t;
            var c1y = p1y + (cy - p1y) * t;
            var c2x = cx + (p2x - cx) * t;
            var c2y = cy + (p2y - cy) * t;
            var tx = c1x + (c2x - c1x) * t;
            var ty = c1y + (c2y - c1y) * t;
            
            animationContext.save();
            // clear old sketch
            animationContext.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
            // draw new line
            animationContext.beginPath();
            animationContext.strokeStyle = '#aaa';
            animationContext.lineWidth = 1;
            animationContext.moveTo(c1x, c1y);
            animationContext.lineTo(c2x, c2y);
            animationContext.stroke();
            // draw points on lines
            drawPoint(animationContext, c1x, c1y, 2, '#0f0');
            drawPoint(animationContext, c2x, c2y, 2, '#0f0');
            // draw point on curve
            drawPoint(animationContext, tx, ty, 3, '#f0f');
            animationContext.restore();
            
            // draw the Bézier curve by hand
            curveContext.lineTo(tx, ty);
            curveContext.stroke();         
        }            
        
        function drawSetup() {
            
            pointsContext.save();
            // lines between p1, c and p2
            pointsContext.strokeStyle = "#ddd";
            pointsContext.lineWidth = 2;
            pointsContext.beginPath();
            pointsContext.moveTo(p1x, p1y);
            pointsContext.lineTo(cx, cy);
            pointsContext.lineTo(p2x, p2y);
            pointsContext.stroke();
            pointsContext.closePath();
            // quadratic Bézier curve
            pointsContext.beginPath();
            pointsContext.strokeStyle = '#999';
            pointsContext.lineWidth = 1;
            pointsContext.moveTo(p1x, p1y);
            pointsContext.quadraticCurveTo(cx,cy, p2x, p2y);
            pointsContext.stroke();                
            pointsContext.restore();
            
            // circles marking p1, c and p2
            drawPoint(pointsContext, p1x, p1y, 5, '#00f');
            drawPoint(pointsContext, cx, cy, 5, '#f00');
            drawPoint(pointsContext, p2x, p2y, 5, '#00f');
            pointsContext.fillText("P1", p1x+10, p1y+10);                
            pointsContext.fillText("C", cx+10,  cy-5);                
            pointsContext.fillText("P2", p2x-20, p2y+10);                
        }
        
        function drawPoint(ctx, x, y, radius, color) {
            ctx.save();
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(x, y, radius, 2 * Math.PI, false);
            ctx.fill();
            ctx.closePath();
            ctx.restore();
        }
        
        function drawGrid() {
            gridContext.save();
            gridContext.strokeStyle = '#ddd';
            gridContext.lineWidth = 1;
            for (var i = 0; i < CANVAS_HEIGHT; i += 20) {
                gridContext.beginPath();
                gridContext.moveTo(0, i);
                gridContext.lineTo(CANVAS_WIDTH, i);
                gridContext.stroke();
            }
            for (var i = 0; i < CANVAS_WIDTH; i += 20) {
                gridContext.beginPath();
                gridContext.moveTo(i, 0);
                gridContext.lineTo(i, CANVAS_HEIGHT);
                gridContext.stroke();
                gridContext.closePath();
            }
            gridContext.restore();
        }
    });
</script>

<p>You can have a look at the source for a complete understanding, but here’s the
important part, edited for clarity:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// constants</span>
<span class="kd">var</span> <span class="nx">CANVAS_WIDTH</span> <span class="o">=</span> <span class="mi">301</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">CANVAS_HEIGHT</span> <span class="o">=</span> <span class="mi">301</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">p1x</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">p1y</span> <span class="o">=</span> <span class="mi">200</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">cx</span> <span class="o">=</span> <span class="mi">140</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">cy</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">p2x</span> <span class="o">=</span> <span class="mi">280</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">p2y</span> <span class="o">=</span> <span class="mi">280</span><span class="p">;</span>

<span class="c1">// basic setup</span>
<span class="kd">var</span> <span class="nx">$t</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#bezier-example-1-t span</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">var</span> <span class="nx">animationCanvas</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#bezier-example-1 .animation</span><span class="dl">'</span><span class="p">).</span><span class="nf">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">animationContext</span> <span class="o">=</span> <span class="nx">animationCanvas</span><span class="p">.</span><span class="nf">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">animationCanvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">CANVAS_WIDTH</span><span class="p">;</span>
<span class="nx">animationCanvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">;</span>

<span class="kd">var</span> <span class="nx">curveCanvas</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#bezier-example-1 .curve</span><span class="dl">'</span><span class="p">).</span><span class="nf">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">curveContext</span> <span class="o">=</span> <span class="nx">curveCanvas</span><span class="p">.</span><span class="nf">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">curveCanvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">CANVAS_WIDTH</span><span class="p">;</span>
<span class="nx">curveCanvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">;</span>
<span class="nx">curveContext</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#777</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">curveContext</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="nx">curveContext</span><span class="p">.</span><span class="nf">beginPath</span><span class="p">();</span>
<span class="nx">curveContext</span><span class="p">.</span><span class="nf">moveTo</span><span class="p">(</span><span class="nx">p1x</span><span class="p">,</span> <span class="nx">p1y</span><span class="p">);</span>
<span class="nx">curveContext</span><span class="p">.</span><span class="nf">stroke</span><span class="p">();</span>

<span class="nf">setInterval</span><span class="p">(</span><span class="nx">updateDemo</span><span class="p">,</span> <span class="mi">1000</span><span class="o">/</span><span class="mi">30</span><span class="p">);</span>

<span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">d</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// direction</span>

<span class="kd">function</span> <span class="nf">updateDemo</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// called 30 times/second to animate</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">t</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">||</span> <span class="nx">t</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">d</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="c1">// change direction</span>
        <span class="nx">curveContext</span><span class="p">.</span><span class="nf">clearRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">CANVAS_WIDTH</span><span class="p">,</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">);</span>
        <span class="nx">curveContext</span><span class="p">.</span><span class="nf">beginPath</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="nx">t</span> <span class="o">+=</span> <span class="mf">0.01</span> <span class="o">*</span> <span class="nx">d</span><span class="p">;</span> <span class="c1">// continue moving</span>
    <span class="nx">$t</span><span class="p">.</span><span class="nf">html</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nf">round</span><span class="p">(</span><span class="nx">t</span><span class="o">*</span><span class="mi">100</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">);</span>
    <span class="c1">// update values</span>
    <span class="kd">var</span> <span class="nx">c1x</span> <span class="o">=</span> <span class="nx">p1x</span> <span class="o">+</span> <span class="p">(</span><span class="nx">cx</span> <span class="o">-</span> <span class="nx">p1x</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">c1y</span> <span class="o">=</span> <span class="nx">p1y</span> <span class="o">+</span> <span class="p">(</span><span class="nx">cy</span> <span class="o">-</span> <span class="nx">p1y</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">c2x</span> <span class="o">=</span> <span class="nx">cx</span> <span class="o">+</span> <span class="p">(</span><span class="nx">p2x</span> <span class="o">-</span> <span class="nx">cx</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">c2y</span> <span class="o">=</span> <span class="nx">cy</span> <span class="o">+</span> <span class="p">(</span><span class="nx">p2y</span> <span class="o">-</span> <span class="nx">cy</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">tx</span> <span class="o">=</span> <span class="nx">c1x</span> <span class="o">+</span> <span class="p">(</span><span class="nx">c2x</span> <span class="o">-</span> <span class="nx">c1x</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">ty</span> <span class="o">=</span> <span class="nx">c1y</span> <span class="o">+</span> <span class="p">(</span><span class="nx">c2y</span> <span class="o">-</span> <span class="nx">c1y</span><span class="p">)</span> <span class="o">*</span> <span class="nx">t</span><span class="p">;</span>
    
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">save</span><span class="p">();</span>
    <span class="c1">// clear old sketch</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">clearRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">CANVAS_WIDTH</span><span class="p">,</span> <span class="nx">CANVAS_HEIGHT</span><span class="p">);</span>
    <span class="c1">// draw new line</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">beginPath</span><span class="p">();</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">#aaa</span><span class="dl">'</span><span class="p">;</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">moveTo</span><span class="p">(</span><span class="nx">c1x</span><span class="p">,</span> <span class="nx">c1y</span><span class="p">);</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">lineTo</span><span class="p">(</span><span class="nx">c2x</span><span class="p">,</span> <span class="nx">c2y</span><span class="p">);</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">stroke</span><span class="p">();</span>
    <span class="c1">// draw points on lines</span>
    <span class="nf">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">c1x</span><span class="p">,</span> <span class="nx">c1y</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#0f0</span><span class="dl">'</span><span class="p">);</span>
    <span class="nf">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">c2x</span><span class="p">,</span> <span class="nx">c2y</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#0f0</span><span class="dl">'</span><span class="p">);</span>
    <span class="c1">// draw point on curve</span>
    <span class="nf">drawPoint</span><span class="p">(</span><span class="nx">animationContext</span><span class="p">,</span> <span class="nx">tx</span><span class="p">,</span> <span class="nx">ty</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="dl">'</span><span class="s1">#f0f</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">animationContext</span><span class="p">.</span><span class="nf">restore</span><span class="p">();</span>
    
    <span class="c1">// draw the new Bezier curve segment</span>
    <span class="nx">curveContext</span><span class="p">.</span><span class="nf">lineTo</span><span class="p">(</span><span class="nx">tx</span><span class="p">,</span> <span class="nx">ty</span><span class="p">);</span>
    <span class="nx">curveContext</span><span class="p">.</span><span class="nf">stroke</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The code is on
<a href="https://github.com/antoineleclair/Understanding-Bezier-Curve">Github</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In a client project I had to draw by hand a quadratic Bézier curve, because the html5 canvas quadraticCurveTo does not return the information about the path drawn and I needed it.]]></summary></entry></feed>