<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Development tales]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://pierrefourgeaud.com/</link><image><url>https://pierrefourgeaud.com/favicon.png</url><title>Development tales</title><link>https://pierrefourgeaud.com/</link></image><generator>Ghost 3.11</generator><lastBuildDate>Wed, 02 Apr 2025 10:23:35 GMT</lastBuildDate><atom:link href="https://pierrefourgeaud.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[So... I wrote my first Rust program...]]></title><description><![CDATA[Rust is known to be a much loved languages as much as it is difficult to learn. It was voted for 4 years, the favorite language on StackOverflow while being adopted very slowly. I am trying to tell the story of my first time with Rust.]]></description><link>https://pierrefourgeaud.com/so-i-wrote-my-first-rust-program/</link><guid isPermaLink="false">5ed398b565f8d948b0717385</guid><category><![CDATA[Rust]]></category><category><![CDATA[Cpp]]></category><category><![CDATA[javascript]]></category><category><![CDATA[typescript]]></category><category><![CDATA[language]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Pierre Fourgeaud]]></dc:creator><pubDate>Sun, 31 May 2020 16:19:15 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1562804501-74f1d98e65cc?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<blockquote><em><u>Disclaimer:</u> Technically, this is not my first Rust program. I played around with rust here and there. However, this is my first "professional" one - meaning that the requirements extended way beyond my prototyping of a small program that would run only on my computer.</em></blockquote><blockquote><em><u>Disclaimer 2:</u> This is not a tutorial about writing Rust in any way - I am just sharing the experience of using Rust for the first time in a professional environment.</em></blockquote><img src="https://images.unsplash.com/photo-1562804501-74f1d98e65cc?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="So... I wrote my first Rust program..."><p>At my current job, my work oscillate between C++ and Typescript. Then we have this new project that came, fairly self-contained, with clear specifications and relatively simple - we decided to jump on the occasion.</p><p>My team was/is responsible for this project, but we synchronized with 2 other teams working on low level software as we all had an interest in trying Rust.</p><h3 id="a-word-on-the-project">A word on the project</h3><p>The project was pretty simple: We needed to develop a library (to be loaded in a huge C++ Software), that would launch a WebSocket server to accept connection from multiple clients. This library should forward all messages coming from the clients to the embedder and allow the embedder to send messages either in broadcast to all clients or only to a specific targeted client.</p><p>The software is running on embedded devices with low resources so performance is definitely a critical component. Finally, the server should allow to be started and stopped when the embedder sees fit.</p><p>A quick search returned that there are 3 WebSockets libraries in Rust that seemed to be "active enough" and with a few stars on Github:</p><ul><li>websocket: <a href="https://crates.io/crates/websocket">https://crates.io/crates/websocket</a></li><li>ws: <a href="https://crates.io/crates/ws">https://crates.io/crates/ws</a></li><li>embedded-websocket: <a href="https://crates.io/crates/embedded-websocket">https://crates.io/crates/embedded-websocket</a></li></ul><p>So it looks like we are covered on that front. Making a library that can be loaded from C++ (from C actually) is "trivial":</p><p>In the cargo.toml you just add this:</p><pre><code class="language-Rust">[lib]
crate-type=["cdylib"]</code></pre><p>And in your rust code, you make callable function pretty easily:</p><pre><code class="language-Rust">#[no_mangle]
pub extern "C" fn hello() {
    println!("Hello World!");
}</code></pre><p>In the C++ code:</p><pre><code class="language-Cpp">extern "C" {
    void hello();
}

int main() {
    hello();
    return 0;
}</code></pre><p>As you guessed, this will print our famous <code>Hello World!</code>.</p><p>Ok, Rust seems to fit all of our "requirements", let's see how it went!</p><h1 id="not-quite-there-yet">Not quite there yet</h1><p>It was actually easy (<a href="https://www.infoworld.com/article/3324488/rust-language-is-too-hard-to-learn-and-use-says-user-survey.html">contrary to popular believes</a>) to get something pretty quickly working and passing all the tests and requirements for this project. It took less than a week to get that working, and integrated into a sample C++ program mocking the functionality of our production code.</p><p>However, getting it working wasn't all - We want the software to run on hundreds of thousands of devices worldwide. We don't want it to break, cause problems and be difficult to maintain.</p><p>Our initial solution contained a thread to run the WebSocket message pump independently from the rest of the software. Fundamentally, this isn't a bad idea, but we have - at Airtame - the rule that <em>"if you can do it without a thread, then do it without a thread"</em>. I will not go into the details of the why, but let's just say that threads bring their own set of issues that are more difficult to reason about and tends to make software more complicated.</p><p>Ultimately, most of us come from a background working with C, so we all were thinking the same thing: can we get something like the <code>select</code> function, so we can have our own loop and handle the incoming and outgoing messages whenever we like? The answer is <em>yes, kind of</em>. The libraries that we tried don't allow that <em>by default</em>, but a couple of them allowed to plug our own loop handling. <em>Great!</em> But digging in that direction shown that it was actually not as simple and straightforward as one would have thought.</p><p>Finally, have the Rust library share some data with C++ is unsafe. Rust is amazing at memory-safety, thread-safety and the likes by removing those issues at compile time. All those advantages vanish when passing data between C++ and Rust.</p><p>Overall, we decided to drop the project in Rust for the time being, we found an easier way, arguably safer and easier to maintain with our current technology stack. <strong><em>But this is not the end of Rust at Airtame. Rust is young and needs to evolve, and we have many incoming projects that will be much more suited for Rust (or Rust suited for them) in the near future.</em></strong></p><h1 id="working-with-rust">Working with Rust</h1><p>Ok, but how was it to work with Rust. The answer was: <strong><em>Pretty amazing</em></strong>. Understand that not everything was an amazing ultra smooth sailing, otherwise we would have stuck with it for production. In this section, I want to go through a couple of things that I think are worth mentioning when talking about Rust.</p><h2 id="correctness">Correctness</h2><p>One of the Rust main focus is correctness. Through a really rich type system and the <strong>ownership model</strong>, Rust guarantees memory-safety and thread-safety.</p><p>When I started to write rust code and play around with it, the compiler/borrow-checker/etc... would be screaming at me constantly. The fact that everything is const unless you explicitly state otherwise, the fact that everything is moved unless you explicitly state that you want to borrow the ownership of a resource, and the fact that every time you borrow the ownership, then the said resource cannot be read or modified anywhere else makes it very different from what I used to... <strong>in a good way</strong>.</p><p>In our jobs, most of us spend long hours writing code, <s>sometimes</s> with deadline that are difficult to meet, with some stress, maybe distractions from our personal life, and so on. None of us is flawless. Having a set of tools supporting you when writing software is priceless.</p><p>Sometimes, it feels like the tool is fighting against you - but trust me, this is for the best :)</p><p><strong><u>Anecdote time:</u></strong></p><p>A few years back, I started the movement to move our Javascript codebase to Typescript. I come from the strongly/statically typed languages world and Javascript always frustrated me by being the literal opposite: a loosely and dynamically typed language. I remember that time, when I stumble upon that function in a code review. That function was taking an ID, great. And there were some operations on the ID in the code of the function. Strings and arithmetic. I was confused. So I asked, the developer, "ok what does the function takes exactly? An Id. Ok, but what is the type of the Id? A number I guess. What do you do this hashing operation that takes a string then? Javascript will convert it to string. Are you sure? Euh.... kinda yes." He was wrong in that case.</p><p>In this example, it is not a case of right or wrong, but more of thinking about the code we write. You - as a developer having to work <strong>with</strong> the compiler and spend more time merging the code is much better than the code breaking in production and cost tens (hundreds) of thousands of dollars to you or your company.</p><p>I managed to convince the different parties that it would be beneficial on the long run. Typescript it was. And for the next 2 years, I heard complaints about how Typescript was stupid because "Of course this variable cannot be undefined, I set it here". Frustration growing but what I found is in 98% of cases (made up number to support my anecdote ;) ), Typescript just caught a potential disastrous production error.</p><p>My point here is that the "compiler" (in case of Typescript, this term is debatable) is here to help and catching the errors as early as in development is the best case scenario for everyone. The QA doesn't have to spent time on a piece of software that has obvious flaws, the business doesn't have to put off fires with clients threatening to leave and so on. (Ultimately, everyone is more than happy to use Typescript today in our teams)</p><p>Rust is amazing at that. Maybe too amazing. I exactly heard that from people. The frustration of not being able to write clunky code just to test out something. Because Rust is not like that. Rust is not for quick and dirty prototyping. Javascript and Python are much more suited for that. But when it comes to code correctness, I grew to love Rust.</p><p>3 sections on the subject from the Rust documentation:</p><ul><li><a href="https://doc.rust-lang.org/1.8.0/book/ownership.html">https://doc.rust-lang.org/1.8.0/book/ownership.html</a></li><li><a href="https://doc.rust-lang.org/1.8.0/book/references-and-borrowing.html">https://doc.rust-lang.org/1.8.0/book/references-and-borrowing.html</a></li><li><a href="https://doc.rust-lang.org/1.8.0/book/lifetimes.html">https://doc.rust-lang.org/1.8.0/book/lifetimes.html</a></li></ul><h2 id="dependency-management">Dependency management</h2><p>Rust comes with a dependency management tools builtin. It might seem like a small feat to some, but I love that.</p><p>I used to code in Ruby that have a pretty nice package manager: <a href="https://bundler.io/">Bundler</a>. Today I use Javascript a lot with <a href="https://www.npmjs.com/">NPM</a> and Elixir/Erlang with <a href="https://hex.pm/">Hex</a>. The only language that I use on a daily basis not having a package manager/dependency manager today is C/C++ (they have a couple of project attempting to solve the issue, but this is not the point here).</p><p>I must say that Cargo is at least as good as the best of the ones on the list mentioned previously. It is pretty fast, simple to use, has all the features that I needed and it seemed to do the job properly. I played with much bigger projects as well where Cargo did a fantastic job.</p><p>You can access the list of packages to use with cargo <a href="https://crates.io/">here</a>. The packages are called <strong>crates</strong>.</p><h2 id="tests">Tests</h2><p>Rust comes with builtin tests functionality. Again, this might sound like a picky thing but I love that I don't have to spend my time evaluating what is good or not. I have one thing, that works and that is used by tons of people. This is all I need to know.</p><p>A small example:</p><pre><code class="language-rust">#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}</code></pre><p>We attempt to write tests as much as we can before going into QA. Having a set of tools at our disposition to do so easily is actually priceless.</p><p>A bit on the subject: <a href="https://doc.rust-lang.org/book/ch11-01-writing-tests.html">https://doc.rust-lang.org/book/ch11-01-writing-tests.html</a></p><h1 id="conclusion">Conclusion</h1><p>To conclude this rather wordy article I would just say that while we decided not to go with Rust for production this time, I can guaranty that I (we) will use Rust in the future. There is a great potential and it was actually fun and enjoyable to write code with it. I totally recommend playing with it.</p><p>If you would like to hear more about writing in Rust, like examples or even a short "tutorial-like", lemme know in the comments!</p><p><u>Some links:</u></p><ul><li>https://<a href="https://www.rust-lang.org/">rust-lang.org</a>: Official Rust website</li><li><a href="https://blog.discord.com/tagged/engineering">https://blog.discord.com/tagged/engineering</a>: Discord talks about some of the real life challenges they have to overcome. They have a couple of articles about Rust that are worth reading.</li><li><a href="https://gist.github.com/brson/a324c83a6af6a8a78dfaa9d33eb9b48e">https://gist.github.com/brson/a324c83a6af6a8a78dfaa9d33eb9b48e</a>: A collection of Rust notable blog posts.</li></ul>]]></content:encoded></item><item><title><![CDATA[React - Don't use index as a key]]></title><description><![CDATA[<p>Over the last couple of weeks I worked on multiple projects which a large <a href="https://reactjs.org/">React</a> codebase spanning from a couple thousand line of codes to more than 100k for one of them.</p><p>Something that stroke me while going through the code was the way the <code>key</code> prop was used when</p>]]></description><link>https://pierrefourgeaud.com/react-do-not-use-index-as-a-key/</link><guid isPermaLink="false">5ea5b9d965f8d948b071729e</guid><category><![CDATA[react]]></category><category><![CDATA[javascript]]></category><category><![CDATA[frontend]]></category><category><![CDATA[web development]]></category><category><![CDATA[react-hooks]]></category><dc:creator><![CDATA[Pierre Fourgeaud]]></dc:creator><pubDate>Sun, 26 Apr 2020 18:23:22 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1581276879432-15e50529f34b?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1581276879432-15e50529f34b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="React - Don't use index as a key"><p>Over the last couple of weeks I worked on multiple projects which a large <a href="https://reactjs.org/">React</a> codebase spanning from a couple thousand line of codes to more than 100k for one of them.</p><p>Something that stroke me while going through the code was the way the <code>key</code> prop was used when rendering an array of elements. In way too many cases the "index" of the array was used. It really felt like it was here more to silence the warning produced by React more than for its actual job: <code>Keys help React identify which items have changed, are added, or are removed</code>.</p><p>The React documentation itself says: </p><blockquote>We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state.</blockquote><p>I want to focus on the last part of this sentence: <code>may cause issues with component state.</code>.</p><h1 id="the-problem">The problem</h1><p>The following section will demonstrate a component that has a list of numbers. Each number will be passed to child component that will take the number and will expose a button that each time it is click will multiply the number by 2:</p><pre><code class="language-JSX">const Parent = () =&gt; {
  const [numbers, setNumbers] = useState([0, 1, 2, 3, 4]);
  
  useEffect(() =&gt; {
    // After 5s, we will remove the midle element of the array.
    setTimeout(() =&gt; {
      setNumbers([0, 1, 3, 4]);
    }, 5000);
  }, []);
  
  return (
  	&lt;main&gt;
      {numbers.map((el, index) =&gt; (
        &lt;Multiply num={el} key={index} /&gt;
      ))}
    &lt;/main&gt;
  )
};

const Multiply = ({num}) =&gt; {
  const [state, setState] = useState(num);
  
  return (
  	&lt;section&gt;
      &lt;div&gt;Initial number: {num}&lt;/div&gt;
      &lt;div&gt;New number: {state}&lt;/div&gt;
      &lt;button onClick={() =&gt; setState(state * 2)}&gt;Multiply&lt;/button&gt;
    &lt;/section&gt;
  );
};
</code></pre><p>The trick part here is the <code>setTimeout</code>. After 5 seconds, we mutate our arrays which triggers re-render of the <code>Multiply</code> components. You can see in the example bellow the issue:</p><figure class="kg-card kg-embed-card"><iframe width="1000" height="500" src="https://codesandbox.io/embed/wrong-index-as-key-652im?fontsize=14&hidenavigation=1&theme=dark" style="width:1000px; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe></figure><p>The new and initial component are not synchronized anymore. During the re-render, React in an attempt to optimize the operation will actually shift the prop and delete the last element of the array. This is where the key is <strong>extremely</strong> important. It helps react keep tracks of the different components and order so you can safely have operations like this one within your components.</p><h1 id="the-solution">The solution</h1><p>How can we then avoid this kind of sneaky issue? As a rule of thumb, I usually generate a unique ID for my objects. Thankfully, in most application of this kind (be it a todo app, a pet management app or a game), when you get elements from your backend API you can get the ID.</p><figure class="kg-card kg-embed-card"><iframe width="1000" height="500" src="https://codesandbox.io/embed/key-used-properly-s09mt?fontsize=14&hidenavigation=1&theme=dark" style="width:1000px; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe></figure><p>You will notice here that I use <code>shortid</code> to generate a short and simple unique ID for my elements. And you can see that after 5s, my array is still looking good.</p><h1 id="the-exception">The exception</h1><p>There is an exception to the rule. Basically, if the array and its elements follow a certain set of rules, you can safely use the index as the <code>key</code>:</p><ol><li>The elements in the array do not change - they are static elements</li><li>The array itself is static: no new elements is added, removed and replaced</li><li>And finally the elements don't have unique IDs.</li></ol><p>Only - and only if - those 3 conditions are met, then using the index as the <code>key</code> will be safe.</p><p>See the previous example but following those rules:</p><figure class="kg-card kg-embed-card"><iframe width="1000" height="500" src="https://codesandbox.io/embed/wrong-key-as-index-but-works-f0moc?fontsize=14&hidenavigation=1&theme=dark" style="width:1000px; height:500px; border:0; border-radius: 4px; overflow:hidden;" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe></figure><p>(Notice that in that case we do not mutate the array).</p><h1 id="conclusion">Conclusion</h1><p>As a rule of thumb, <strong>I never use index as a key</strong>. But if you end up in a situation where the array that you are about to display exposes elements without unique identifiers, I would refer you to the exception rules. If the first 2 points are met, feel free to use the index safely - otherwise generate ids for your object.</p><p>Some more documentation on the subject:</p><ul><li><a href="https://reactjs.org/docs/lists-and-keys.html">https://reactjs.org/docs/lists-and-keys.html</a></li><li><a href="https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318">https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Game Engine Series - Prologue]]></title><description><![CDATA[The Game Engine Series follow the development of a Game Engine sharing experience and progress along the way. The prologue is the 1st article of the series.]]></description><link>https://pierrefourgeaud.com/game-engine-series-prologue/</link><guid isPermaLink="false">5e6e7166884a4611582c5433</guid><category><![CDATA[Game Engine]]></category><category><![CDATA[Cpp]]></category><category><![CDATA[Series]]></category><category><![CDATA[Devlog]]></category><category><![CDATA[Game Engine Series]]></category><dc:creator><![CDATA[Pierre Fourgeaud]]></dc:creator><pubDate>Sun, 15 Mar 2020 20:20:31 GMT</pubDate><media:content url="https://pierrefourgeaud.com/content/images/2020/03/bert-sz-rhNff6hB41s-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://pierrefourgeaud.com/content/images/2020/03/bert-sz-rhNff6hB41s-unsplash.jpg" alt="Game Engine Series - Prologue"><p>This article with be the first of a long list about the development of my own Game Engine. This series of posts will document the progress made during development, re-transcribe the struggles, but also progresses, the thinking process and the cool stuffs found along the way.</p><p>This first article will set the base for this series: Where does this idea come from? Why doing this? And what will be the goal?</p><h2 id="the-beginning">The beginning</h2><p>Since I started programming, I have had in mind to learn how to build video games. Every single game that I play, I am obsessed with find which engine it uses, how is it made, etc... . Around 4 years ago (might be 5 or 6), I started to think about investing time in learning how to create video games. But as everything related to programming, I was more obsessed with the low level functioning of the systems that make games possible more than having a clear project in mind.<br><br>Don't get me wrong, I have a couple of ideas of video games I want to produce - one being written and partially scripted already. But my need for understanding of the subsystem was winning at the time. And still is.<br><br>I then started to develop my own game engine in C++, starting with the 3D engine, following development tutorial for <a href="https://learnopengl.com">OpenGL</a>. I came to a point where I could load 3D models, render textures, skybox, having a basic <a href="https://learnopengl.com/Lighting/Basic-Lighting">Phong lighting model</a>, a basic system of plugins and a "fairly" abstracted 3D rendering engine. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pierrefourgeaud.com/content/images/2020/03/ss_codehero1.png" class="kg-image" alt="Game Engine Series - Prologue"><figcaption>Example of what the engine could do. (low end computer with integrated graphics, no Nvidia or AMD</figcaption></figure><p>But as I was doing that in parallel of a full time job, sometime motivation faded out and eventually I basically stopped committing.<br><br>For around 1.5 years, I barely committed to the repo and improved what was in place. Until 2 weeks ago.</p><h2 id="the-new-beginning">The new beginning</h2><p>Behind this catchy section title is actually the truth.<br><br>2 weeks ago, I decided to start a refactoring (more of a rewrite) of the engine, with more defined goals and a slightly different approach.<br>First, let me list the points and objectives that will <u>stay the same and where I will be focusing my next few years</u>:</p><ul><li><strong>Cross platform</strong>: I want the engine to run on Windows, Linux and MacOs. Hopefully I will add more platforms to it in the future but this on those 3 platform that my experience is.</li><li><strong>Abstracted</strong>: I want a sufficient level of abstraction that it will be easy to replace the Audio engine, the rendering engine, the physics engine, add plugins, etc...</li><li><strong>2D and 3D</strong>: I want to be able to choose rendering pipeline for both 2D and 3D, and having the subsystems working with it.</li><li><strong>Editor</strong>: I still want to have a Game/Level editor coming with the engine.</li><li><strong><u>Open Source</u></strong></li><li>There are many many more ideas that will be listed on the <a href="https://github.com/pierrefourgeaud/CodeHero">repo of the project</a>. Those are just the main lines of thinking, and what will drive the overall architecture and process around the Engine.</li></ul><p><u>What will change now:</u></p><ul><li>I want to build games with it. Meaning that throughout development, I want to produce examples demoing and proving that the engine works and is made for building games (example: <a href="https://en.wikipedia.org/wiki/Tetris">Tetris</a>, <a href="https://en.wikipedia.org/wiki/R-Type">R-Type</a>, small 3D puzzles, ...)</li><li>I want to divide the project development into small challenges: for example cool module system, plugins, UI renderer, Bloom effect, ... And document them, write about them, ...</li><li>Implement only features that are understood and used in an example: in the previous project, I implemented some small bits because some tutorial said it was nice but never dug into what was the real purpose and all.</li><li>Finally I want to be less picky. I am learning, this is a fun and learning experience. I used to be stressed not to do the right thing. But this is ok, I will do mistake and I will fix them.</li></ul><h2 id="next-steps">Next steps</h2><p>I started a <code>refactoring-0.1</code> branch that intends to rewrite the code up until a similar state as before.</p><p>I will spend a lot of time in playing around with an architecture that will enable:</p><ul><li>A good module system that enable hot reload of some subsystem (I had this on my todo list of things to play with for years)</li><li>A good plugin system to write proper plugins to load resources, enable algorithm, etc...</li><li>Abstractions of the platforms and the rendering API/Driver</li><li>And finally of the rendering pipelines: 2D/3D/UI.</li></ul><p>As mentioned, this project is a learning experience, mistakes will be made, non optimal code will be made (do not forget, no code review, no peer help... yet, and no experience in that domain...).</p><h2 id="conclusion">Conclusion</h2><p>The project is named <strong>CodeHero</strong> (this is up to change), it is hosted on github.com: <a href="https://github.com/pierrefourgeaud/CodeHero">CodeHero</a>.</p><p>I hope to make great progress and share experience as often as possible on this "devlog".</p>]]></content:encoded></item></channel></rss>