<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Molecule.dev Blog</title>
    <link>https://www.molecule.dev/blog</link>
    <description>Engineering notes and updates from Molecule.dev.</description>
    <language>en</language>
    <lastBuildDate>Tue, 17 May 2022 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://www.molecule.dev/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Uncommon but useful Git commands</title>
      <link>https://www.molecule.dev/blog/useful-uncommon-git-commands</link>
      <guid isPermaLink="true">https://www.molecule.dev/blog/useful-uncommon-git-commands</guid>
      <pubDate>Tue, 17 May 2022 00:00:00 GMT</pubDate>
      <description>A cheatsheet for Git commands Molecule.dev uses internally on a regular basis.</description>
      <category>engineering</category>
      <category>git</category>
      <category>assemble</category>
      <category>mlcl</category>
      <category>cli</category>
      <category>tools</category>
      <category>cheatsheet</category>
      <content:encoded><![CDATA[<p>This is a cheatsheet for useful Git commands that we use semi-regularly, mostly for internal use as a quick future reference but I figured I would share.</p>
<h3 id="change-commit-author-date">Change commit author date</h3>
<pre><code class="language-sh">git commit --amend --no-edit --date=&quot;Wed Mar 30 22:45:55 2022 +0200&quot;
</code></pre>
<h3 id="get-last-commit-to-modify-file">Get last commit to modify file</h3>
<pre><code class="language-sh">git log -n 1 --format=&quot;%H %s&quot; -- path/to/file
</code></pre>
<h3 id="get-first-commit">Get first commit</h3>
<pre><code class="language-sh">git log --reverse --format=&quot;%H %s&quot; | head -1
</code></pre>
<h3 id="find-commits-with-modified-code-matching-some-string">Find commits with modified code matching some string</h3>
<pre><code class="language-sh">git log --branches -S&#x27;some code you need to fix&#x27;
</code></pre>
<h3 id="find-commits-with-modified-code-matching-some-regular-expression">Find commits with modified code matching some regular expression</h3>
<pre><code class="language-sh">git log --branches -G&#x27;some code you need to fix&#x27;
</code></pre>
<h3 id="create-a-commit-message-with-a-trailer">Create a commit message with a trailer</h3>
<pre><code class="language-sh">git commit -am &#x27;add something&#x27; --trailer=&quot;Molecule: apiPackageManager=NPM, apiLanguage=TypeScript&quot;
</code></pre>
<h3 id="find-dangling-commits">Find dangling commits</h3>
<pre><code class="language-sh">git fsck --lost-found 2&gt;&amp;1 | grep &quot;dangling commit&quot;
</code></pre>
<h3 id="wipe-unused-history">Wipe unused history</h3>
<pre><code class="language-sh">git for-each-ref --format=&quot;delete %(refname)&quot; refs/original | git update-ref --stdin
git reflog expire --expire=now --expire-unreachable=now --all
git gc --prune=now --aggressive
</code></pre>
<h3 id="remove-untracked-files-and-directories">Remove untracked files and directories</h3>
<pre><code class="language-sh">git clean -f -d
</code></pre>
<h3 id="delete-all-remote-branches">Delete all remote branches:</h3>
<pre><code class="language-sh">git branch -r | grep origin/ | grep -v &#x27;index$&#x27; | grep -v HEAD| cut -d/ -f2 | while read line; do git push origin :$line; done;
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>A system integration tool, not a framework</title>
      <link>https://www.molecule.dev/blog/system-integration-tool-not-framework</link>
      <guid isPermaLink="true">https://www.molecule.dev/blog/system-integration-tool-not-framework</guid>
      <pubDate>Fri, 06 May 2022 00:00:00 GMT</pubDate>
      <description>The long term vision for Molecule.dev is to give developers and businesses a reliable way to instantly integrate any tool and feature into their systems.</description>
      <category>about</category>
      <category>engineering</category>
      <category>git</category>
      <category>assemble</category>
      <category>mlcl</category>
      <category>integration</category>
      <category>tools</category>
      <content:encoded><![CDATA[<p>As of 2022, there are roughly <a href="https://evansdata.com/press/viewRelease.php?pressID=278">25 million software developers</a> around the world. By 2030, that number is expected to almost double to 45 million. JavaScript (including TypeScript) is the most popular language, followed by Python, Java, variations of C, and PHP. Up and coming languages are Go, Kotlin, R, Scala, and Rust, to name just a few. The most active and emerging sectors include web and mobile applications, backend services, machine learning, robotics, and maybe crypto.</p>
<p>The demand for software engineers is higher than ever, and it grows by the day. Custom software provides immense benefits to businesses and their customers. It is a necessity for most businesses to keep up with the modern world.</p>
<p>If you&#x27;ve kept up with software progression over the years, you&#x27;ve probably noticed a pattern emerge where we repeatedly recreate the same things in different ways, often using different technologies, languages, tools, platforms, and paradigms. The primary reason for this repetition is that software (mostly) exists to fulfill human needs, and we&#x27;ve grown to expect certain functionality from the software that we use. We almost always log in. Sometimes we want to be notified. Businesses need to be paid, and the easier it is for customers to do that, the better. It takes significant amounts of time and effort to seamlessly integrate all of these things into the custom software that powers businesses.</p>
<p>It&#x27;s impossible to know the exact percentage, but it&#x27;s safe to say that at least 50% of software projects fail. Various sources report failure rates ranging from 25% to 80%. The common theme behind these failures is a lack of time. Developers everywhere routinely underestimate the amount of time it takes to build quality software. Much of the reason for this comes down to a lack of experience, unclear requirements, and/or factors beyond their control.</p>
<p>To be competitive in today&#x27;s markets, you <em>will</em> need to integrate with third party services and platforms, each with their own sets of requirements and restrictions which evolve over time. You have no control over any of this. It can take a very surprising amount of time to properly integrate these systems.</p>
<p>Nowadays, we have a myriad of amazing libraries, tools, and services we can use to make development easier, but we still spend entirely too much time manually integrating them to produce the result that we <em>really</em> want, things that are actually functional and useful, complete with all of the integrated functionality that users have come to expect. Many example git repositories and app starter kits are generously available, but they are all very limited in what they do. They all still require a lot of work to turn into something that meets real world needs.</p>
<p>Are millions of developers really going to continue reimplementing the same integrations for systems and functionality that we know we need? I don&#x27;t think so, but collectively, we&#x27;re not quite there yet. We&#x27;ve refined our tools. Some systems and best practices have solidified. These things are not going anywhere for the forseeable future, so why not take the next step and reduce the time and cost of integration to almost nothing? This is the problem Molecule.dev aims to solve.</p>
<p>Our approach is based on tools and workflows already used on a daily basis by developers everywhere. The goal is to instantly produce the kind of output that teams would expect if they themselves implemented it over months (or years) for their specific stack and requirements. The result is something that developers have full control over, without the need to learn (or be locked into) some elaborate framework or wait on someone else to implement any extra functionality they need in the form of issues, forks, and pull requests. (Some functionality could certainly be packaged and installed as dependencies, but that is a discussion for a later date. Molecule.dev primarily provides the glue between all of your dependencies and integrated systems.)</p>
<p>You can <a href="https://assemble.molecule.dev">check out what we have so far</a> and instantly assemble full-stack applications using any combination of TypeScript, JavaScript, React, PostgreSQL, Capacitor, PWA, Android, iOS, macOS, Windows, Linux, Styled Components, themes, typical user authentication, OAuth (Google, Twitter, GitHub, GitLab), push notifications, Stripe, Apple Pay, Google Pay, emails, file uploads, unit tests, documentation, logging, and deployment. The resulting fully functional app is capable of being published to app stores within the same day, after some minor setup.</p>
<p>99.9% of it is free and open source with an Apache 2.0 license, and there is a lot more in the works. Once we&#x27;ve made it even easier to add more options and integrations, it will be opened up to contributors. Long term, the goal is to provide a tool which skips all of the most boring and tedious system integrations, while combining all of the most popular tools and libraries, so that developers can focus on building what really matters.</p>
<p>Thanks for reading!</p>]]></content:encoded>
    </item>
    <item>
      <title>Using Git trailers, grep, and cherry-pick to generate unlimited combinations of features, stacks, and platforms</title>
      <link>https://www.molecule.dev/blog/using-git-for-unlimited-feature-stack-platform-combinations</link>
      <guid isPermaLink="true">https://www.molecule.dev/blog/using-git-for-unlimited-feature-stack-platform-combinations</guid>
      <pubDate>Tue, 03 May 2022 00:00:00 GMT</pubDate>
      <description>We built a tool using advanced Git methods to assemble full-stack apps with any combination of languages, features, and integrations.</description>
      <category>engineering</category>
      <category>git</category>
      <category>assemble</category>
      <category>mlcl</category>
      <category>cli</category>
      <category>tools</category>
      <content:encoded><![CDATA[<p><em>&quot;What would you say you do here?&quot; –<a href="https://www.imdb.com/title/tt0151804/">Office Space (1999)</a></em></p>
<p>What would you say professional software engineers <em>do</em>? The job usually involves a lot more than writing code. Meetings. User feedback. Bug fixes. Design decisions. Choosing the right tools. Cost-benefit analysis. Team building. Delegation. The list goes on.</p>
<p>The job can vary significantly, depending on the role and level of experience, but at the end of the day, it all comes down to producing code which solves real problems and meets business needs. The effective output of software engineering can be measured as code committed, not by the number of lines or even the number of commits, but by the problems solved, features added, and systems integrated.</p>
<p>If you&#x27;re a professional software engineer, there&#x27;s at least a 99.99% chance you know what <a href="https://git-scm.com/">Git</a> is, and you probably use it almost every day. The tangible work you produce is typically a series of <a href="https://github.com/git-guides/git-commit">Git commits</a> and <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches">branches</a>. The end result is the current version of your application.</p>
<p>What if you had a way to skip all of the time-consuming integration work, a way to pick and choose exactly the commits you need to produce your desired application? That is exactly what we&#x27;re doing here.</p>
<p>Almost every user-oriented, data-driven app in existence shares much of the same core functionality, especially today, as users have grown accustomed to features like two-factor authentication, receiving emails, push notifications, dark mode, in-app payments, biometrics, cross-platform support, and everything else. For any serious application, users tend to expect all of this functionality at a minimum, and it can be extremely time-consuming to integrate all of it on your own in a manageable, extendable way, specific to your stack. Why should developers everywhere spend their time reinventing the wheel, over and over again?</p>
<p>Tools and technologies improve, standards change, and sometimes it is necessary to upgrade your stack and your codebase to keep up, but overall, the core functionality remains the same. Our mission with Molecule.dev and its open source tools is to give developers everywhere a way to skip reinventing the common core functionality and jump straight to customizing and building what really matters, without being locked into a single particular paradigm or ecosystem. Ideally, you&#x27;ll be able to instantly add, remove, swap, and upgrade features, platforms, and maybe even eventually entire languages, and it will all work exactly as expected. (You can already do this with the current options!)</p>
<h2 id="introducing-mlcl">Introducing <code>mlcl</code></h2>
<p>To help make all of this possible, we&#x27;ve developed a command line tool called <a href="https://github.com/molecule-dev/mlcl"><code>mlcl</code></a>. It is designed around patterns and conventions already integral to nearly every developers&#x27; daily workflow, regardless of language or platform. Many of the commands resemble <code>git</code> commands, as it mostly uses <code>git</code> under the hood.</p>
<p>Choose combinations of the most popular battle-tested libraries, platforms, and features, depending on your individual needs, and <code>mlcl</code> generates your fully functional codebase by <a href="https://git-scm.com/docs/git-cherry-pick">cherry-picking</a> a series of carefully crafted commits from various branches, relevant to your selection.</p>
<p>While it initially produces very framework-like results, the output is not a framework. It is not limited to any single way of doing things, and you have full control over every line of code. Obviously, <em>some</em> structure and opinion is required, but we try to remain as agnostic as possible. The end result is a composition of well-defined, pure functions.</p>
<p>The biggest upside to the cherry-picking approach is that there is no need to devise some elaborate framework with a plugin system or anything like that. All that is necessary is good code and modular git commits.</p>
<p>Another upside is that every line of code has a purpose. There is no extra theoretical code or bloat for you to sift through. What you see is exactly what you get. The surface area is exactly as large as you need it to be, which helps you maintain a simple, predictable mental model.</p>
<h2 id="how-does-it-work">How does it work?</h2>
<p>A few approaches were considered before finally settling on the simplest one, which works with no extra setup and relies only on <code>git</code>.</p>
<p>Git has a handy feature called &quot;trailers&quot;, which is just a line (or lines) of text at the end of git commit messages. Historically, only a <code>Signed-off-by</code> trailer was officially supported by using the <code>--signoff</code> (or <code>-s</code>) option, but a <code>--trailer</code> option was added roughly a year ago (since version 2.14) to officially support any trailer. (For older versions, you can manually add the line(s) in the proper format.) These trailers provide useful information about commits. For example, GitHub looks for a special <code>Co-authored-by</code> trailer, which allows you to <a href="https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors">attribute a commit to multiple authors</a>, visible within GitHub&#x27;s UI.</p>
<p>For codebases designed to work with <code>mlcl</code>, we use trailers to specify the language, library, platform, and/or feature relevant to the commit.</p>
<p>For example, we&#x27;ll run a <code>git commit</code> command with messages and trailers which looks something like this:</p>
<pre><code>git commit -m &#x27;enable user authentication&#x27; --trailer Molecule=&#x27;appLanguage=TypeScript, appRenderer=React, userAuthentication=Typical&#x27;
</code></pre>
<blockquote>
<p><strong>See more</strong>
Take a look at the commits throughout the various branches of <a href="https://github.com/molecule-dev/molecule"><code>molecule</code></a>!</p>
</blockquote>
<p>Each <code>mlcl</code> branch is created (as necessary) as <a href="https://www.npmjs.com/package/object-hash">object-hashes</a> of the various combinations of selections. This means that as we add more options, the number of potential branches will grow exponentially. It also means that if you make the same selection as other people, you will clone the same branch when starting out.</p>
<p>It doesn&#x27;t really matter which branch the original commits are in. There are only two requirements:</p>
<ol>
<li>The author date for each commit must be in the necessary (working) order.</li>
<li>Each integration should be developed on its own, ideally within the branch for the minimal feature set. For example, for payment platforms, Stripe, Apple Pay, and Google Pay each have their own branch. If multiple are selected, they will be automatically combined together during assembly.</li>
</ol>
<blockquote>
<p><strong>Note</strong>
Developers building on top of the resulting codebase(s) don&#x27;t have to worry about any of this. You can build your app and commit your code however you want, unless you want to eventually make your own contributions. More on that later!</p>
</blockquote>
<p>To assemble every codebase, <code>mlcl</code> runs a fairly complex <code>git log --grep</code> operation to find (and sort) all of the relevant commits for your selection, and then runs <code>git cherry-pick</code> for each one with <a href="https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver">custom Git merge drivers</a> to automatically resolve any conflicts.</p>
<p>We&#x27;re currently using only two custom Git merge drivers - one for JSON, and another for all other files using <a href="https://git-scm.com/docs/git-merge-file"><code>git merge-file</code></a>&#x27;s built-in <code>--diff3</code> and <code>--union</code> options. We&#x27;ll add more drivers as they become necessary.</p>
<p>When writing code for various options, it definitely helps to have enough experience with Git to know how it will attempt to merge. On rare occasion, placeholder comments and static code boundaries are necessary, but overall, Git is really smart with how it merges every commit. There are also probably some linting configurations which would help enforce mergeable code. For example, cherry-pickable items in an array should each be on their own line with trailing commas.</p>
<p>It&#x27;s also worth noting that the Git history of each branch is rebased (overwritten) on a regular basis, but this is necessary and expected, as the Git history itself is the result we&#x27;re after.</p>
<p>This approach seems to work very well and produces exactly the code we want. It also has the added benefit of forcing us to write clean, decoupled, modular code, such that every feature and integration can be added, removed, and/or swapped using simple <code>git</code> commands.</p>
<h2 id="whats-next-for-mlcl">What&#x27;s next for <code>mlcl</code>?</h2>
<p>At the time of this writing, <code>mlcl</code> is very specific to Molecule.dev. One of the short-term goals is to generalize it, refine it, and add more commands to make it easier to go back and forth between branches, checkout the necessary commits to add features and fix bugs, and apply changes to all other relevant branches. It already has all of this, but it can be much more user-friendly. There may also be a more efficient way to <code>pick</code> all of the commits at once by passing a custom editor to <code>git rebase</code> instead of cherry-picking one by one.</p>
<p>Right now, <a href="https://github.com/molecule-dev/mlcl">the public version of <code>mlcl</code></a> queries the Molecule.dev API for the relevant commits to cherry pick, but the next major version will include all of the following additional commands (pulled and polished from the version we&#x27;re using internally):</p>
<ul>
<li>
<p><strong><code>mlcl select --show</code></strong></p>
<p>Shows the current selection.</p>
</li>
<li>
<p><strong><code>mlcl select --feature=Value</code></strong></p>
<p>Selects the necessary branch for the specified feature(s), while leaving the other selections intact.</p>
<p>For example:</p>
<pre><code class="language-sh">mlcl select --appThemes=Light
</code></pre>
<pre><code class="language-sh">mlcl select --appThemes=Dark
</code></pre>
<pre><code class="language-sh">mlcl select --appThemes=&quot;Light, Dark&quot;
</code></pre>
<p>Or multiple features at a time:</p>
<pre><code class="language-sh">mlcl select --appUi=Tailwind --pushNotifications=Enabled --paymentPlatforms=&quot;Apple Pay, Google Pay&quot;
</code></pre>
</li>
<li>
<p><strong><code>mlcl checkout &lt;hash&gt;</code></strong></p>
<p>Checks out a known <code>mlcl</code> branch hash and updates the selection to match.</p>
</li>
<li>
<p><strong><code>mlcl rebase</code></strong></p>
<p>Rebases the selection&#x27;s relevant commits onto the current branch.</p>
</li>
<li>
<p><strong><code>mlcl rebase --show</code></strong></p>
<p>Shows the selection&#x27;s relevant commits which would be rebased onto the current branch.</p>
</li>
<li>
<p><strong><code>mlcl rebase --all</code></strong></p>
<p>Rebases every known selection&#x27;s relevant commits onto their respective branches.</p>
</li>
<li>
<p><strong><code>mlcl rebase --show-all</code></strong></p>
<p>Shows every known selection&#x27;s relevant commits which would be rebased onto their respective branches.</p>
</li>
<li>
<p><strong><code>mlcl rebase --all --continue=&lt;hash&gt;</code></strong></p>
<p>If for some reason the original <code>mlcl rebase --all</code> failed, you can continue at a specific hash to avoid having to rebase every prior branch again.</p>
</li>
<li>
<p><strong><code>mlcl rebase --all --feature=Value</code></strong></p>
<p>Rebases every known selection&#x27;s relevant commits for the specified feature(s) onto their respective branches. Useful to update only the branches relevant to a specific feature (or features) so that no time is wasted rebasing unaffected branches.</p>
</li>
<li>
<p><strong><code>mlcl sync [remote]</code></strong></p>
<p>Synchronizes every branch with the remote.</p>
</li>
</ul>
<p>Some other useful additions might be things like:</p>
<ul>
<li><code>mlcl find</code> for quickly finding exactly where certain code originated.</li>
<li><code>mlcl branch</code> with an interactive human readable list of each branch&#x27;s features to quickly go from branch to branch.</li>
<li><code>mlcl backup</code> to make quick backups of repositories, as the original Git history is overwritten regularly.</li>
</ul>
<h2 id="whats-next-for-moleculedev">What&#x27;s next for Molecule.dev?</h2>
<p>The future isn&#x27;t 100% certain right now, but I would like to think that this is the beginning of something that can seriously raise the bar for both developers and end users. The long term idea is not only to save developers insane amounts of time and costs, but to also improve the way we think about building software, making it easier and more accessible for everyone to build and use high quality applications.</p>
<p>The hardest part of building the underlying tech is done. It took much longer than expected, but you can now assemble fully functional full-stack starter applications with the most common features, integrations, and platforms, tailored to your needs. Now that the foundation is in place and it works (better than expected!), adding more options should be <em>relatively</em> quick and easy.</p>
<p>Eventually (hopefully sooner rather than later), Molecule.dev will have a marketplace and a job board.</p>
<ul>
<li>As a buyer: Imagine having a vast selection of features and integrations to choose from, where you can instantly add, remove, and swap each one, knowing that you&#x27;re getting high quality code tailored specifically to your needs.</li>
<li>As a seller: Whether it&#x27;s a UI library, an icon pack, templates, a database, a CDN, anything really... you&#x27;ll have a place where you can scale your work (which ultimately boils down to git commits, right?) to any number of buyers.</li>
</ul>
<p>There is a lot of potential here, and refining these tools and practices is an endeavor worth pursuing. If you disagree, please let me know! I would love to hear your thoughts and feedback.</p>
<h2 id="stay-in-touch">Stay in touch!</h2>
<p>Keep up with weekly update digests by signing up via <a href="https://assemble.molecule.dev">assemble.molecule.dev</a> and enabling the newsletter.</p>
<p>Our goal is to revolutionize the way people think about building reliable, high quality software.</p>
<p>You can show your support with a monthly subscription or a license. If you cannot yet afford it, use Molecule.dev to build something awesome, something people want, and then subscribe or purchase a premium license via <a href="https://assemble.molecule.dev">assemble.molecule.dev</a> when you can.</p>
<p>Also be sure to:</p>
<ul>
<li>Share this blog post</li>
<li>Follow <a href="https://twitter.com/molecule_dev">@molecule_dev</a> on Twitter</li>
<li>Star all of <a href="https://github.com/molecule-dev">our public repositories on GitHub</a></li>
</ul>
<p>Thanks for reading!</p>]]></content:encoded>
    </item>
    <item>
      <title>Two extremely useful custom React hooks we use everywhere</title>
      <link>https://www.molecule.dev/blog/two-custom-react-hooks</link>
      <guid isPermaLink="true">https://www.molecule.dev/blog/two-custom-react-hooks</guid>
      <pubDate>Thu, 16 Dec 2021 00:00:00 GMT</pubDate>
      <description>Learn about how we simplified state management within our React apps.</description>
      <category>engineering</category>
      <category>frontend</category>
      <category>ui</category>
      <category>react</category>
      <category>hooks</category>
      <category>typescript</category>
      <content:encoded><![CDATA[<p>If I&#x27;ve learned anything from being glued to a code editor for (probably too many) years, it&#x27;s that the simplest approach is almost always the best one.</p>
<p>In the case of modern front end engineering and React especially, you can reduce everything down to two simple concepts...</p>
<ol>
<li>Rendering the current state</li>
<li>Updating the state</li>
</ol>
<p>Realistically, it&#x27;s a bit more complex than that. You&#x27;ll often need to consider shared application state and internal component state. Updates can also occur asynchronously with potentially many different states along the way, possibly arriving at an unexpected state when there&#x27;s an error or if the user aborts the asynchronous operation. You may also need to consider performance when rendering lots of data or animating complex scenes.</p>
<p>But when it all comes down to it, everything is just a function of state.</p>
<p>With that in mind, we have a couple of super simple React hooks that we use everywhere. Combined with a design pattern which we&#x27;ll cover later in this blog post, it&#x27;s hard to imagine needing much more for the vast majority of cases. We still use basic hooks like <a href="https://reactjs.org/docs/hooks-reference.html#usestate"><code>useState</code></a>, <a href="https://reactjs.org/docs/hooks-reference.html#useeffect"><code>useEffect</code></a>, <a href="https://reactjs.org/docs/hooks-reference.html#usememo"><code>useMemo</code></a>, and <a href="https://reactjs.org/docs/hooks-reference.html#useref"><code>useRef</code></a> as necessary, but as far as complex state management goes, the following two custom hooks are usually all we need.</p>
<h2 id="useasyncextendedstate"><code>useAsyncExtendedState</code></h2>
<p>This hook works almost exactly like React&#x27;s built-in <a href="https://reactjs.org/docs/hooks-reference.html#usestate"><code>useState</code></a> hook, but with two additions. It&#x27;s probably easiest to understand by example.</p>
<ol>
<li>
<p>It includes an extra method to extend the current state.</p>
<p>Define the <code>State</code> interface.</p>
<pre><code class="language-ts">interface State {
  foo: string
  bar: string
}
</code></pre>
<p>Use the hook.</p>
<pre><code class="language-ts">const [ state, setState, extendState ] = useAsyncExtendedState&lt;State&gt;({
  foo: `foo`,
  bar: `bar`
})
</code></pre>
<p>Setting state works as usual.</p>
<pre><code class="language-ts">setState({ foo: `Hello`, bar: `World!` })
setState(state =&gt; ({ foo: `Hello`, bar: `World!` }))
</code></pre>
<p>Or you can extend the state.</p>
<pre><code class="language-ts">// Set `foo` while keeping `bar`.
extendState({ foo: `Hello` })

// Set `foo` while keeping `bar`, as a function of the current state.
extendState(state =&gt; ({ foo: state.foo.toUpperCase() }))
</code></pre>
<p>Try not to abuse <code>extendState</code>. It exists to make your code more concise and readable when you&#x27;re merging partial states many times throughout your codebase.</p>
<blockquote>
<p>It should become clear later in this article why we&#x27;ve decided to include <code>extendState</code>. (The API returns partial states for certain endpoints commonly used for every resource.)</p>
</blockquote>
<blockquote>
<p><strong>Tip</strong>
With Molecule.dev, we try to give you as much control over your Molecule&#x27;s code as possible. All of <a href="https://github.com/molecule-dev/molecule/blob/mlcl-9239f003850cf8b8c8bdc881b5c2e93853b6fb58/src/hooks/useAsyncExtendedState.ts">this code is open source</a>, so you can quickly change it to suit your needs and preferences.</p>
</blockquote>
</li>
<li>
<p>You can pass promises to both <code>setState</code> and <code>extendState</code> to asynchronously update the state.</p>
<p>Suppose you have a function which asynchronously fetches data from your API and returns the data as the next state.</p>
<pre><code class="language-ts">const fetchState = () =&gt; API.client.get&lt;State&gt;(`data`).then(response =&gt; {
  return response.data
})
</code></pre>
<p>Alternatively, the promise may also resolve a function of the current state, similar to <code>setState(state =&gt; ({ ...state }))</code>.</p>
<pre><code class="language-ts">const fetchState = () =&gt; API.client.get&lt;State&gt;(`data`).then(response =&gt; {
  return (state: State) =&gt; {
    return response.data
  }
})
</code></pre>
<p>Call the asynchronous function and pass the promise to <code>setState</code>. The state will eventually be set to the resolved value.</p>
<pre><code class="language-ts">setState(fetchState())
</code></pre>
<p>Similarly for <code>extendState</code>, suppose you have a function which asynchronously fetches partial data from your API.</p>
<pre><code class="language-ts">const fetchPartialState = () =&gt; API.client.get&lt;Partial&lt;State&gt;&gt;(`data`).then(response =&gt; {
  return response.data
})

// Or a function of the current state
const fetchPartialState = () =&gt; API.client.get&lt;Partial&lt;State&gt;&gt;(`data`).then(response =&gt; {
  return (state: State) =&gt; {
    return response.data
  }
})
</code></pre>
<p>Call <code>fetchPartialState</code> and pass the promise to <code>extendState</code>. The state will eventually be extended by the resolved value.</p>
<pre><code class="language-ts">extendState(fetchPartialState())
</code></pre>
<blockquote>
<p>Note: The <code>setState</code> and <code>extendState</code> functions accept promises, not functions. In other words, the usage is <code>setState(asyncFunc())</code>, not <code>setState(asyncFunc)</code>. See <a href="https://github.com/molecule-dev/molecule/issues/2">this issue</a> for more information.</p>
</blockquote>
</li>
</ol>
<h2 id="usepromise"><code>usePromise</code></h2>
<p>More often than not, when something is happening asynchronously, you&#x27;ll want to display some feedback to the user.</p>
<p>This hook accepts any asynchronous function (i.e., a function which returns a promise) and returns a new asynchronous function wrapping the original, along with the state of the promise plus <code>cancel</code> and <code>reset</code> methods.</p>
<p>For example, suppose we want to fetch data from the API and display the current state of the request to the user.</p>
<p>Define the <code>State</code> interface.</p>
<pre><code class="language-ts">interface State {
  foo: string
  bar: string
}
</code></pre>
<p>Define a function which returns a promise. In this example, we&#x27;ll fetch API data and resolve it as <code>State</code>.</p>
<pre><code class="language-ts">const read = (id: string) =&gt; API.client.get&lt;State&gt;(`things/${id}`).then(response =&gt; {
  return response.data
})
</code></pre>
<p>Pass the function to the <code>usePromise</code> hook.</p>
<pre><code class="language-ts">const [ readThingRequest, readThing ] = usePromise(read)
</code></pre>
<p><code>readThingRequest</code> contains the state of the promise plus a <code>reset</code> method, defined below:</p>
<pre><code class="language-ts">interface PromiseState&lt;T&gt; {
  status?: `pending` | `resolved` | `rejected`
  promise?: Promise&lt;T&gt;
  value?: Awaited&lt;T&gt;
  error?: Error
  cancel?: (message?: string) =&gt; void
}

type PromiseStateWithReset&lt;T&gt; = PromiseState&lt;T&gt; &amp; {
  reset: (keys?: Array&lt;keyof PromiseState&lt;T&gt;&gt;) =&gt; void
}
</code></pre>
<p>If you would like to initialize the <code>readThingRequest</code> state, pass the initial state as the second argument:</p>
<pre><code class="language-ts">const [ readThingRequest, readThing ] = usePromise(read, {
  status: `resolved`,
  value: state
})
</code></pre>
<p><code>readThing</code> has the same function signature as <code>read</code>. In other words, you&#x27;ll call <code>readThing(id)</code> the same way you&#x27;d call <code>read(id)</code>.</p>
<p>Initially, before <code>readThing</code> is called, the <code>readThingRequest</code> will be an empty object (other than the <code>reset</code> method) if an initial state was unprovided.</p>
<p>When you call <code>readThing(id)</code>, the <code>readThingRequest</code> state becomes:</p>
<pre><code class="language-ts">const readThingRequest = {
  status: `pending`,
  promise, // the promise returned by `read(id)`
  cancel, // a method to cancel the asychronous update
  reset
}
</code></pre>
<p>When the promise has resolved, the <code>readThingRequest</code> state then becomes:</p>
<pre><code class="language-ts">const readThingRequest = {
  status: `resolved`,
  value, // the resolved value
  reset
}
</code></pre>
<p>If there is an error and the promise is rejected:</p>
<pre><code class="language-ts">const readThingRequest = {
  status: `rejected`,
  error, // an instance of `Error`
  reset
}
</code></pre>
<p>If <code>readThingRequest.cancel</code> was called before the promise resolves, the <code>readThingRequest</code> state immediately becomes:</p>
<pre><code class="language-ts">const readThingRequest = {
  status: `rejected`,
  error, // an instance of `Error` with the message passed to `readThingRequest.cancel`, if any
  reset
}
</code></pre>
<p>To cancel updates for the current promise, <em>with</em> an error message:</p>
<pre><code class="language-ts">readThingRequest.cancel(&#x27;Cancelled!&#x27;)
</code></pre>
<p>To cancel updates for the current promise, <em>without</em> an error message:</p>
<pre><code class="language-ts">readThingRequest.cancel()
</code></pre>
<blockquote>
<p>Note: Cancelling only prevents the state update. The asynchronous function you&#x27;ve called will continue unless you have a way to stop it. For example, in our case where we&#x27;re using <code>axios</code> for API requests, we would need to incorporate its <a href="https://axios-http.com/docs/cancellation">cancellation methods</a>. This is beyond the scope of this article though, as <code>usePromise</code> can be used for <em>any</em> asynchronous operation.</p>
</blockquote>
<p>To reset the state entirely:</p>
<pre><code class="language-ts">readThingRequest.reset()
</code></pre>
<p>Or if you want to reset a specific value (<code>readThingRequest.error</code>, for example):</p>
<pre><code class="language-ts">readThingRequest.reset(`error`)
</code></pre>
<p>Or multiple (both <code>readThingRequest.status</code> and <code>readThingRequest.error</code>, for example):</p>
<pre><code class="language-ts">readThingRequest.reset([`status`, `error`])
</code></pre>
<p>You may also call <code>readThing(id)</code> more than once, and in which case, the current <code>readThingRequest.value</code> will remain until it is overridden by the next resolved value. So if you would like to reset the value when refetching:</p>
<pre><code class="language-ts">readThingRequest.reset([`value`])
readThing(id)
</code></pre>
<blockquote>
<p>Note: If you&#x27;re combining <code>readThing</code> with the <code>useAsyncExtendedState</code> hook, you probably don&#x27;t care about <code>readThingRequest.value</code>. More on that below.</p>
</blockquote>
<h2 id="combining-the-two-hooks">Combining the two hooks</h2>
<p>The <code>usePromise</code> hook pairs especially well with the <code>useAsyncExtendedState</code> hook.</p>
<p>At the start of this post, I mentioned a design pattern which makes everything clean and predictable. We&#x27;ve been using it in the example(s) above, but now we&#x27;ll make it more obvious.</p>
<p>API resources typically have a handful of their own routes, usually following a <a href="https://restfulapi.net/">RESTful</a> design with CRUD (create, read, update, and delete) methods.</p>
<p><a href="https://github.com/molecule-dev/molecule">Molecule.dev&#x27;s core application code</a> is structured such that each API resource has its own directory with an index which exports methods for each route.</p>
<p>Suppose we have an API resource called a <code>thing</code> with CRUD methods:</p>
<pre><code class="language-ts">import { client } from &#x27;../../client&#x27;
import * as types from &#x27;./types&#x27;

export const create = (props: types.CreateProps): Promise&lt;types.SuccessResponse&gt; =&gt; (
  client.post(`things`, props)
)

export const read = (id: string): Promise&lt;types.SuccessResponse&gt; =&gt; (
  client.get(`things/${id}`)
)

export const update = (id: string, props: types.UpdateProps): Promise&lt;types.SuccessPartialResponse&gt; =&gt; (
  client.patch(`things/${id}`, props)
)

export const del = (id: string): Promise&lt;types.SuccessPartialResponse&gt; =&gt; (
  client.delete(`things/${id}`)
)
</code></pre>
<p>We&#x27;ll import these methods and use them with the <code>useAsyncExtendedState</code> and <code>usePromise</code> hooks.</p>
<p>As an example, let&#x27;s create a component to read some <code>thing</code> by id and allow the user to update it.</p>
<p>First, let&#x27;s cover some relevant type definitions.</p>
<p>Every RESTful API resource will have an <code>id</code>, <code>createdAt</code> date, and <code>updatedAt</code> date:</p>
<pre><code class="language-ts">/**
 * The resource&#x27;s properties.
 */
export interface Props {
  /**
   * Usually a UUID.
   */
  id: string
  /**
   * When the resource was created.
   * 
   * Usually an ISO 8601 timestamp.
   */
  createdAt: string
  /**
   * When the resource was last updated.
   * 
   * Usually an ISO 8601 timestamp.
   */
  updatedAt: string
}
</code></pre>
<p>Our <code>thing</code> resource will have a <code>description</code> property:</p>
<pre><code class="language-ts">import * as resourceTypes from &#x27;../types&#x27;

/**
 * The thing&#x27;s properties returned by the API.
 */
export interface Props extends resourceTypes.Props {
  /**
   * The thing description.
   */
  description?: string
}
</code></pre>
<blockquote>
<p><strong>Tip</strong>
We&#x27;ve also defined types for every API request and response, which you can <a href="https://github.com/molecule-dev/molecule/tree/mlcl-9239f003850cf8b8c8bdc881b5c2e93853b6fb58/src/API/resource">check out on GitHub</a>.</p>
</blockquote>
<p>For the sake of example, we&#x27;ll create an <code>Editor</code> component with a predefined initial state and render the current state with an input for updating the <code>description</code>. An &quot;Update thing&quot; button will request an API update when clicked, extending the state with the response data, and we&#x27;ll render a cancel button along with the current request status and error, if defined.</p>
<pre><code class="language-tsx">import React from &#x27;react&#x27;
import { useAsyncExtendedState, usePromise } from &#x27;../../hooks&#x27;
import { update } from &#x27;../../API/resource/thing&#x27;
import { types } from &#x27;../../API/resource/thing&#x27;

export const Editor = () =&gt; {
  const [ state, setState, extendState ] = useAsyncExtendedState&lt;types.Props&gt;({
    id: `733e26aa-97ea-46d7-b4d4-e556a5f37d68`,
    createdAt: `2021-12-17T12:32:13.981Z`,
    updatedAt: `2021-12-17T12:32:13.981Z`,
    description: `This is a simple but powerful design pattern!`
  })

  const [ updateThingRequest, updateThing ] = usePromise((updateProps: types.UpdateProps) =&gt; (
    update(state.id, updateProps).then(response =&gt; response.data.props)
  ))

  return (
    &lt;div&gt;
      &lt;div&gt;
        {`Created thing: ${new Date(state.createdAt).toLocaleString()}`}
      &lt;/div&gt;

      &lt;div&gt;
        {`Updated thing: ${new Date(state.updatedAt).toLocaleString()}`}
      &lt;/div&gt;

      &lt;textarea
        value={state.description}
        onChange={event =&gt; extendState({ description: event.target.value })}
      /&gt;

      &lt;button onClick={() =&gt; extendState(updateThing({ description: state.description }))}&gt;
        {updateThingRequest.status === `pending` ? `Updating thing...` : `Update thing`}
      &lt;/button&gt;

      {updateThingRequest.cancel &amp;&amp; (
        &lt;button onClick={() =&gt; updateThingRequest.cancel(`cancelled`)}&gt;
          Cancel update
        &lt;/button&gt;
      )}

      {updateThingRequest.status &amp;&amp; (
        &lt;div&gt;
          {`Request status: ${updateThingRequest.status}`}
        &lt;/div&gt;
      )}
      
      {updateThingRequest.error &amp;&amp; (
        &lt;div style={{ color: `red` }}&gt;
          {`Error: ${updateThingRequest.error.message}`}
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  )
}
</code></pre>
<blockquote>
<p>In case you missed it, the concise bit of code combining the two hooks is found on the button&#x27;s <code>onClick</code> handler:</p>
<pre><code class="language-ts">extendState(updateThing({ description }))
</code></pre>
</blockquote>
<h3 id="see-it-in-action">See it in action</h3>
<p><em>(An interactive demo lived here on the original post. The CodeSandbox link below has the same example.)</em></p>
<p>This example is also available to play with on <a href="https://codesandbox.io/s/nifty-brown-n7suy?file=/src/App/Thing/Editor.tsx">CodeSandbox</a>.</p>
<h3 id="check-out-the-source">Check out the source</h3>
<p>You can find the code for these hooks on our GitHub <a href="https://github.com/molecule-dev/molecule/tree/mlcl-9239f003850cf8b8c8bdc881b5c2e93853b6fb58/src/hooks">here</a>.</p>
<p>If you want to get started on an app and API using these design patterns, git clone the <a href="https://github.com/molecule-dev/molecule"><code>molecule</code></a> repository. Thorough documentation and guides are included.</p>
<pre><code>git clone https://github.com/molecule-dev/molecule.git
cd molecule
npm install
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>You can combine these two hooks to cleanly manage asynchronous state at any level throughout your app, for nearly anything you can think of.</p>
<p>These design patterns help you simplify your thinking and the code itself by separating concerns in a way that is predictably consistent and incredibly easy to manage and build upon. This naturally leads to both a better user experience and a better developer experience.</p>
<ul>
<li>Define asynchronous functions on their own.</li>
<li>Asynchronously set or extend state with a one-liner, via the <code>useAsyncExtendedState</code> hook.</li>
<li>To show the user the current state of any asynchronous operation, pass the async function to the <code>usePromise</code> hook and render the promise state.</li>
</ul>
<p>We use this for everything throughout applications built with Molecule.dev - signing up, logging in, the users themselves, enabling 2FA, payments, subscriptions, plan changes, device management, push notifications... everything!</p>
<p>If you like this and want to learn more, check out <a href="https://github.com/molecule-dev">our GitHub</a> and get started building something of your own by cloning Molecule.dev&#x27;s core TypeScript app and API. After installing Node dependencies, you&#x27;ll be greeted with documentation generated by <a href="https://typedoc.org/">TypeDoc</a> where you can dig into more internals and play around.</p>
<p>If you&#x27;re a professional web developer, where you&#x27;re an indie dev or a CTO, and you want to save months of development time on cross-platform apps, visit <a href="https://www.molecule.dev">Molecule.dev</a> to assemble a codebase tailored to your specific needs. You&#x27;re guaranteed a rock solid foundation from which you and your team can scale with ease.</p>
<p>Also be sure to follow us on Twitter <a href="https://twitter.com/molecule_dev">@molecule_dev</a> for regular updates and more posts like this one!</p>]]></content:encoded>
    </item>
    <item>
      <title>And we&apos;re live! 🚀</title>
      <link>https://www.molecule.dev/blog/launch</link>
      <guid isPermaLink="true">https://www.molecule.dev/blog/launch</guid>
      <pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate>
      <description>The official beginning of Molecule.dev! Learn more about where its headed.</description>
      <category>about</category>
      <category>updates</category>
      <category>launch</category>
      <content:encoded><![CDATA[<p>Today marks the official beginning of Molecule.dev!</p>
<p>We have many exciting things coming.</p>
<p>Molecule.dev exists because there are many incredible tools and services to choose from when building full-stack applications, and while they make our lives as developers much easier, it is often unpredictably time consuming to glue them all together in a way that meets real world needs.</p>
<p>Over the years, we at Fullstacked have built nearly every type of application under the sun. Every app is unique but almost always shares core functionality. Molecule.dev polishes this core functionality and provides the most solid foundation possible for whatever you need, saving months of development time, energy, and costs. It is the perfect fit for any project, designed for teams of professional developers of varying experience, whether you&#x27;re a fledgling startup or an established brand.</p>
<p>The software engineering ecosystem churn that we&#x27;ve seen over these past decades is both intimidating and exciting. Libraries, tools, and services have come and gone, and it&#x27;s only going to continue improving from here. Molecule.dev takes the best of them all and makes it insanely easy for you to jump straight to building your own unique features, immediately ready for release on every platform.</p>
<p>If you haven&#x27;t already, check out <a href="https://www.molecule.dev">Molecule.dev</a> and assemble your own Molecule. If you&#x27;re interested but not ready to dive in, you can submit your request without checking out. The direction we take Molecule depends heavily on your input!</p>
<p>We&#x27;re adding and improving options every week, and we&#x27;ll be writing often about engineering, design decisions, and inner workings, so keep an eye on this blog and follow <a href="https://twitter.com/molecule_dev">@molecule_dev</a> on Twitter for regular updates.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
