<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Just Enough Software</title>
    <link>https://justenough.software/</link>
    <description>Recent content on Just Enough Software</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 27 Jul 2023 14:38:00 -0500</lastBuildDate><atom:link href="https://justenough.software/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Local-only architecture</title>
      <link>https://justenough.software/posts/local-only-architecture/</link>
      <pubDate>Thu, 27 Jul 2023 14:38:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/local-only-architecture/</guid>
      <description>Continuing on from our review of the project&amp;rsquo;s end goal, let&amp;rsquo;s sketch out the architecture for the frontend, with a focus just on local-only functionality.
Keeping things as simple as possible, I want a text field that we can edit, and which will persist our changes across reloads of the page. Lucky for us, automerge has a tutorial that does just that.
Since we&amp;rsquo;ve sorted out our build system, nothing there should need to change, and whatever functionality we get locally during development should be the same after deployment (though the state will be different for both).</description>
      <content>&lt;p&gt;Continuing on from our &lt;a href=&#34;https://justenough.software/posts/revisiting-our-end-goal/&#34;&gt;review of the project&amp;rsquo;s end goal&lt;/a&gt;, let&amp;rsquo;s sketch out the architecture for
the frontend, with a focus just on local-only functionality.&lt;/p&gt;
&lt;p&gt;Keeping things as simple as possible, I want a text field that we can edit, and which will
persist our changes across reloads of the page. Lucky for us, automerge &lt;a href=&#34;https://automerge.org/docs/tutorial/introduction/&#34;&gt;has a tutorial&lt;/a&gt; that does
just that.&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;ve sorted out our build system, nothing there should need to change, and whatever
functionality we get locally during development should be the same after deployment (though the
state will be different for both).&lt;/p&gt;
&lt;p&gt;All that taken together:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the Fulcro code to have a text field we can edit, but without persistence&lt;/li&gt;
&lt;li&gt;Follow the automerge tutorial, sorting out how to integrate automerge with Fulcro, and
ultimately introducing persistence with automerge.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While each of those items has many sub-items, some of which I&amp;rsquo;m aware of and some I&amp;rsquo;m sure will
surprise me, I think that&amp;rsquo;s a good enough breakdown to get moving.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Revisiting our end goal</title>
      <link>https://justenough.software/posts/revisiting-our-end-goal/</link>
      <pubDate>Thu, 27 Jul 2023 14:24:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/revisiting-our-end-goal/</guid>
      <description>In our previous post, Serving up Fulcro, we learned about what it takes to build and serve the frontend assets for our app. At the end of that post I listed out some Next Steps, but before we pursue those next steps I want to step back and revisit the end goal to make sure that the next thing we figure out is the right next step.
In the AutoFlare Overview post I talked about wanting to learn about three things:</description>
      <content>&lt;p&gt;In our previous post, &lt;a href=&#34;https://justenough.software/posts/serving-up-fulcro/&#34;&gt;Serving up Fulcro&lt;/a&gt;, we learned about what it takes to build and serve the
frontend assets for our app. At the end of that post I listed out some Next Steps, but before we
pursue those next steps I want to step back and revisit the end goal to make sure that the next
thing we figure out is the right next step.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&#34;https://justenough.software/posts/serverless-automerge/&#34;&gt;&lt;code&gt;AutoFlare&lt;/code&gt; Overview post&lt;/a&gt; I talked about wanting to learn about three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare&amp;rsquo;s cloud offerings&lt;/li&gt;
&lt;li&gt;Fulcro&lt;/li&gt;
&lt;li&gt;Automerge CRDT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So far, we&amp;rsquo;ve learned enough about Cloudflare&amp;rsquo;s offerings to identify the top-level offerings
we&amp;rsquo;ll need to use, even if we haven&amp;rsquo;t learned enough about all of them to use them yet.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve also learned enough about Fulcro to build frontend assets with the Pages service, though
nothing else about Fulcro yet.&lt;/p&gt;
&lt;p&gt;Finally, we&amp;rsquo;ve learned nothing about Automerge.&lt;/p&gt;
&lt;p&gt;At the end of this project, I&amp;rsquo;d like to have a repo I can deploy with Cloudflare Pages that
supports multi-user, multi-machine text editing with Automerge, using Fulcro as the library for
handling the FE code.&lt;/p&gt;
&lt;p&gt;Since Automerge was built with local-first development in mind, we can distinguish between two
major architectural phases of this project:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Local only&lt;/li&gt;
&lt;li&gt;Local and Remote&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first phase only requires frontend assets, and thus doesn&amp;rsquo;t require us to sort out Pages
Functions or Durable Objects at all. The second phase requires the same things as the first
phase, plus an understanding of Functions and Durable Objects. Even if we were to start with
Remote Only first, we&amp;rsquo;d still have to sort out most of the same things as the Local Only phase &amp;ndash;
defining the UI, handling text input, leveraging automerge &amp;ndash; along with all of the things the
Remote phase needs, so going Remote Only as a first step doesn&amp;rsquo;t save us anything.&lt;/p&gt;
&lt;p&gt;With that in mind, figuring out how the local-first approach should look sounds like the next,
incremental step in this project.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll sketch out a rough shape for the necessary components needed for this local-only approach in
the next post. See you then!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Serving up Fulcro</title>
      <link>https://justenough.software/posts/serving-up-fulcro/</link>
      <pubDate>Thu, 27 Jul 2023 10:10:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/serving-up-fulcro/</guid>
      <description>Now that we understand the general requirements for hosting FE assets and backend functionality with Pages, let&amp;rsquo;s figure out how to get that working with Fulcro.
Pages has a long list of supported frameworks, but, perhaps unsurprisingly, none of them are a CLJS framework. Luckily, remembering from the Pages overview post, we can either build the assets ourselves and commit them to our repo, or, possibly, we can specify a custom build command that will build the assets for us as part of the Pages infrastructure.</description>
      <content>&lt;p&gt;Now that we understand the general requirements for hosting FE assets and backend functionality
with Pages, let&amp;rsquo;s figure out how to get that working with Fulcro.&lt;/p&gt;
&lt;p&gt;Pages has a long list of &lt;a href=&#34;https://developers.cloudflare.com/pages/framework-guides/&#34;&gt;supported frameworks&lt;/a&gt;, but, perhaps unsurprisingly, none of them are a
CLJS framework. Luckily, remembering from &lt;a href=&#34;https://justenough.software/posts/pages-functions-overview/&#34;&gt;the Pages overview post&lt;/a&gt;, we can either build the assets
ourselves and commit them to our repo, or, possibly, we can specify a custom build command that
will build the assets for us as part of the Pages infrastructure.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;rsquo;ll do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get a barebones Fulcro app that we can build and view locally&lt;/li&gt;
&lt;li&gt;Sort out how we can build this via the Pages CI/CD infrastructure.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;barebones-fulcro-app&#34;&gt;Barebones Fulcro App&lt;/h2&gt;
&lt;p&gt;Originally, this section was going to be about creating a barebones app with the Fulcro
Template, but after going down that route for a bit I realized that the frontend code relies on
having the backend code running, which isn&amp;rsquo;t what I need or want at the moment.&lt;/p&gt;
&lt;p&gt;So instead of that, we&amp;rsquo;re going to follow the &lt;a href=&#34;https://book.fulcrologic.com/#_create_your_project&#34;&gt;Fulcro book&lt;/a&gt; to get the bare minimum frontend code
working.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve created the &lt;a href=&#34;https://github.com/futuro/autoflare&#34;&gt;autoflare&lt;/a&gt; repo to house the code for this project.&lt;/p&gt;
&lt;p&gt;To get this barebones Pages app to work, we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;code&gt;index.html&lt;/code&gt; file in whatever our &lt;code&gt;build directory&lt;/code&gt; is&lt;/li&gt;
&lt;li&gt;said index file to have the necessary Fulcro things &amp;ndash; a div to attach to, and a script tag
pointing at the generated js file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;generating-the-frontend-assets&#34;&gt;Generating the frontend assets&lt;/h3&gt;
&lt;p&gt;With &lt;a href=&#34;https://github.com/futuro/autoflare/commit/e7382fa3acfe5236615b133ae8c6d6ab82824c8b&#34;&gt;this commit&lt;/a&gt; we&amp;rsquo;ve got a barebones Fulcro app that we can see locally via &lt;code&gt;npx shadow-cljs server&lt;/code&gt; and for which we can generate a JS file via &lt;code&gt;npx shadow-cljs compile :main&lt;/code&gt; or, to pass
it through the Closure Compiler&amp;rsquo;s optimizations, &lt;code&gt;npx shadow-cljs release :main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After experimentation with the Cloudflare Pages build environment, I discovered that it has
neither a JDK nor the Clojure binary, the first of which is necessary no matter what, and the
second we can skip &amp;ndash; if we want to &amp;ndash; by defining our dependencies in just the
&lt;code&gt;shadow-cljs.edn&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not exactly sure how that&amp;rsquo;ll play out with my dev environment, but the docs seem to
indicate that it should be fine. The dev process was:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, move dependency management &lt;a href=&#34;https://github.com/futuro/autoflare/commit/ff21b01&#34;&gt;into the shadow-cljs.edn file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Next, try installing the jdk with apt, first &lt;a href=&#34;https://github.com/futuro/autoflare/commit/60ccfea&#34;&gt;without sudo&lt;/a&gt; and then &lt;a href=&#34;https://github.com/futuro/autoflare/commit/ced28ad&#34;&gt;with sudo&lt;/a&gt;, though neither
of those worked out&lt;/li&gt;
&lt;li&gt;Finally, I discovered that the JDK can work just from an archive file, so I &lt;a href=&#34;https://github.com/futuro/autoflare/commit/31756f8&#34;&gt;downloaded it&lt;/a&gt;
and (after fixing &lt;a href=&#34;https://github.com/futuro/autoflare/commit/5c2eb68&#34;&gt;a typo&lt;/a&gt;), got a successful build!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;summary-and-next-steps&#34;&gt;Summary and next steps&lt;/h2&gt;
&lt;p&gt;So the build environment comes with the necessary versions of NPM/Yarn, we add a JDK via an
archive file, and then Shadow CLJS does the rest. If we ever need or want to use deps.edn in our
build process, we can likely download a binary for Clojure in much the same way we dl&amp;rsquo;ed the
JDK.&lt;/p&gt;
&lt;p&gt;Next up is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learning about how Functions work&lt;/li&gt;
&lt;li&gt;Figuring out how to incorporate that into the build process&lt;/li&gt;
&lt;li&gt;Figuring out how that fits into the dev experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See you next time!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Pages overview</title>
      <link>https://justenough.software/posts/pages-functions-overview/</link>
      <pubDate>Mon, 24 Jul 2023 16:09:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/pages-functions-overview/</guid>
      <description>My core goal with this post is to break down how Pages, and Pages Functions, work together.
Pages This link has a good overview of how to set up Pages for deployment. The two that interest me are the Git provider set up, and the wrangler cli. My default is to use the git provider configuration, as I&amp;rsquo;d like to deploy this on push to the main branch, but the wrangler cli may have some useful functionality to learn about.</description>
      <content>&lt;p&gt;My core goal with this post is to break down how Pages, and Pages Functions, work together.&lt;/p&gt;
&lt;h2 id=&#34;pages&#34;&gt;Pages&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://developers.cloudflare.com/pages/get-started/guide/#connect-your-git-provider-to-pages&#34;&gt;This link&lt;/a&gt; has a good overview of how to set up Pages for deployment. The two that interest me are
the Git provider set up, and the &lt;code&gt;wrangler&lt;/code&gt; cli. My default is to use the git provider
configuration, as I&amp;rsquo;d like to deploy this on push to the main branch, but the &lt;code&gt;wrangler&lt;/code&gt; cli may
have some useful functionality to learn about.&lt;/p&gt;
&lt;p&gt;There is also &lt;a href=&#34;https://developers.cloudflare.com/pages/framework-guides/deploy-anything/&#34;&gt;this link&lt;/a&gt;, which covers how to deploy anything with Cloudflare Pages. From this
page, we get the following quote&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unlike many of the framework guides, the build command and build directory for your site are going
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;to be completely custom. If you do not need a build step, leave the &lt;span style=&#34;font-weight:bold&#34;&gt;*Build command*&lt;/span&gt; field empty and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;specify a &lt;span style=&#34;font-weight:bold&#34;&gt;*Build output directory*&lt;/span&gt;. The build output directory is where your application&amp;#39;s content
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lives.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So to serve up frontend content, the core thing we need is some kind of asset(s) in the build
output directory, and potentially we can use a build command if we&amp;rsquo;d like.&lt;/p&gt;
&lt;p&gt;This begs the question: what needs to be in the build output directory for pages to work?&lt;/p&gt;
&lt;p&gt;Looking at the output of the &lt;code&gt;hugo&lt;/code&gt; command &amp;ndash; specifically the files inside it&amp;rsquo;s output
directory &amp;ndash; my first though was that just an &lt;code&gt;index.html&lt;/code&gt; was sufficient, but I saw a &lt;code&gt;404.html&lt;/code&gt;
file, and didn&amp;rsquo;t see a reference to that in the index.html file, so now I&amp;rsquo;m not sure.&lt;/p&gt;
&lt;p&gt;Luckily, perusing the Platform section of the Pages docs leads me to &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/serving-pages/&#34;&gt;this page&lt;/a&gt;, which explains
how Pages chooses to route requests to your assets.&lt;/p&gt;
&lt;p&gt;This explains how the &lt;code&gt;404.html&lt;/code&gt; file is served by Pages, and also how the &lt;code&gt;index.html&lt;/code&gt; file is
served up (plus all the other files).&lt;/p&gt;
&lt;p&gt;The non-SPA behavior is described as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;**&lt;/span&gt; Route matching
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   If an HTML file is found with a matching path to the current route
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   requested, Pages will serve it. Pages will also redirect HTML pages to
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   their extension-less counterparts: for instance, &lt;span style=&#34;color:#a6e22e&#34;&gt;=/contact.html=&lt;/span&gt; will be
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   redirected to &lt;span style=&#34;color:#a6e22e&#34;&gt;=/contact=&lt;/span&gt;, and &lt;span style=&#34;color:#a6e22e&#34;&gt;=/about/index.html=&lt;/span&gt; will be redirected to &lt;span style=&#34;color:#a6e22e&#34;&gt;=/about/=&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;**&lt;/span&gt; Not Found behavior
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   You can define a custom page to be displayed when Pages cannot find a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   requested file by creating a &lt;span style=&#34;color:#a6e22e&#34;&gt;=404.html=&lt;/span&gt; file. Pages will then attempt to
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   find the closest 404 page. If one is not found in the same directory as
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   the route you are currently requesting, it will continue to look up the
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   directory tree for a matching &lt;span style=&#34;color:#a6e22e&#34;&gt;=404.html=&lt;/span&gt; file, ending in &lt;span style=&#34;color:#a6e22e&#34;&gt;=/404.html=&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   This means that you can define custom 404 paths for situations like &lt;span style=&#34;color:#a6e22e&#34;&gt;=/blog/404.html=&lt;/span&gt; and &lt;span style=&#34;color:#a6e22e&#34;&gt;=/404.html=&lt;/span&gt;, and Pages will automatically render
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   the correct one depending on the situation.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since Fulcro is a React app, we&amp;rsquo;re probably going to make more use of how it handles SPAs, which
is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-org&#34; data-lang=&#34;org&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;If your project does not include a top-level &lt;span style=&#34;color:#a6e22e&#34;&gt;=404.html=&lt;/span&gt; file, Pages assumes that you are deploying a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;single-page application. This includes frameworks like React, Vue, and Angular. Pages&amp;#39; default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;single-page application behavior matches all incoming paths to the root (&lt;span style=&#34;color:#a6e22e&#34;&gt;=/=&lt;/span&gt;), allowing you to
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;capture URLs like &lt;span style=&#34;color:#a6e22e&#34;&gt;=/about=&lt;/span&gt; or &lt;span style=&#34;color:#a6e22e&#34;&gt;=/help=&lt;/span&gt; and respond to them from within your SPA.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So to get Pages to serve an SPA, we should exclude a &lt;code&gt;404.html&lt;/code&gt; file. I&amp;rsquo;m not exactly sure if
there&amp;rsquo;s a way to override this at the moment, but can simply avoid creating a 404 file for the
time being.&lt;/p&gt;
&lt;h2 id=&#34;functions&#34;&gt;Functions&lt;/h2&gt;
&lt;p&gt;Now that we&amp;rsquo;ve got an overview of how to serve a custom frontend &amp;ndash; i.e. one that doesn&amp;rsquo;t use a
known framework &amp;ndash; let&amp;rsquo;s take a quick overview of Functions to get a lay of the land.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/get-started/#create-a-function&#34;&gt;The overview&lt;/a&gt; covers most of what we need to know.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s a &lt;code&gt;/functions&lt;/code&gt; directory which contains js files&lt;/li&gt;
&lt;li&gt;The filenames, sans-extension, define routes&lt;/li&gt;
&lt;li&gt;The functions we define in these files have a defined API&lt;/li&gt;
&lt;li&gt;We can alter the routing logic in some way, though I haven&amp;rsquo;t dug into how just yet&lt;/li&gt;
&lt;li&gt;We can also choose an &lt;code&gt;Advanced Mode&lt;/code&gt; to define our Functions with a &lt;code&gt;_workers.js&lt;/code&gt; file
instead of the &lt;code&gt;/functions&lt;/code&gt; directory approach&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for how you tie the frontend and backend together, I suspect looking at the &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/routing/&#34;&gt;Routing docs&lt;/a&gt;, the
&lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/api-reference/&#34;&gt;API Reference docs&lt;/a&gt;, and the &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/middleware/&#34;&gt;Middleware docs&lt;/a&gt; are the proper next things to look at. Routing
should help us understand how to ensure FE requests go to the right function in the BE, the API
ref will tell us how to actually build the BE functionality, and the middleware docs will tell
us how to add things like authentication, as needed.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Two possible avenues open before us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Figure out how to build a barebones Fulcro app with Cloudflare Pages&lt;/li&gt;
&lt;li&gt;Dig into the aforementioned Functions docs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See you next time!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Cloudflare</title>
      <link>https://justenough.software/posts/cloudflare-autoflare-mk1/</link>
      <pubDate>Mon, 24 Jul 2023 13:39:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/cloudflare-autoflare-mk1/</guid>
      <description>To host this app, I&amp;rsquo;ll need the following things:
Something to host the static assets, e.g. the html/css/js. Something to handle the state synchronization across clients To host a site that would allow for multi-user alteration of the content, static assets alone won&amp;rsquo;t be enough, as we&amp;rsquo;ll need a way to synchronize our changes across users. While automerge has many ways to exchange changes &amp;ndash; essentially anything that can faithfully transmit or store binary data &amp;ndash; if we want an always-on node that can act as a post-office of sorts, we&amp;rsquo;ll need to build the code that takes the binary data and puts it on that node.</description>
      <content>&lt;p&gt;To host this app, I&amp;rsquo;ll need the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Something to host the static assets, e.g. the html/css/js.&lt;/li&gt;
&lt;li&gt;Something to handle the state synchronization across clients&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To host a site that would allow for multi-user alteration of the content, static assets alone
won&amp;rsquo;t be enough, as we&amp;rsquo;ll need a way to synchronize our changes across users. While automerge has
many ways to exchange changes &amp;ndash; essentially anything that can faithfully transmit or store
binary data &amp;ndash; if we want an always-on node that can act as a post-office of sorts, we&amp;rsquo;ll need to
build the code that takes the binary data and puts it on that node.&lt;/p&gt;
&lt;p&gt;To that end, I want to explore the solutions Cloudflare has for storing and retrieving data.&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to start with the assumption that we&amp;rsquo;ll use Cloudflare Pages to host the site. From
this, it looks like there&amp;rsquo;s &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/&#34;&gt;Pages Functions&lt;/a&gt; and &lt;a href=&#34;https://developers.cloudflare.com/workers/&#34;&gt;Cloudflare Workers&lt;/a&gt; as options. The sites aren&amp;rsquo;t
super clear on the differences, or when you&amp;rsquo;d use one over the other, but a quick look at the
listed tutorials for both shows a &lt;a href=&#34;https://github.com/cloudflare/workers-chat-demo&#34;&gt;chat demo for Workers&lt;/a&gt; and nothing similar for Functions.&lt;/p&gt;
&lt;p&gt;That doesn&amp;rsquo;t mean Functions would be insufficient, but I wanted to note that as a strong signal
that Workers is &lt;em&gt;probably&lt;/em&gt; the right fit for what we&amp;rsquo;re looking for.&lt;/p&gt;
&lt;p&gt;The demo uses Durable Objects &amp;ndash; another Cloudflare tech &amp;ndash; among some other things, so I
suspect Durable Object will be in use no matter what.&lt;/p&gt;
&lt;h2 id=&#34;what-s-the-difference-between-functions-and-workers&#34;&gt;What&amp;rsquo;s the difference between Functions and Workers?&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/&#34;&gt;Functions overview page&lt;/a&gt; has this to say about Pages Functions&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pages Functions allows you to build full-stack applications by executing code on the Cloudflare
network with &lt;a href=&#34;https://justenough.software/workers/&#34;&gt;Cloudflare Workers&lt;/a&gt;. With Functions, you can introduce application aspects such as
authenticating, handling form submissions, or working with middleware. Use Functions to deploy
server-side code to enable dynamic functionality without running a dedicated server.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My immediate read of this is that Functions is some more sugar on top of Workers, and is meant
to offer something more than just what Workers can do, or simplify something about Workers, or
perhaps is a name for integrating Workers into a Pages application. I&amp;rsquo;m not exactly sure, so
we&amp;rsquo;ll keep digging.&lt;/p&gt;
&lt;p&gt;Reading through the &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/get-started/&#34;&gt;Functions getting-started doc&lt;/a&gt;, it&amp;rsquo;s sounding more and more like the primary
functionality is that you add Workers function definitions in a special directory, and it can
automagically sort out routing issues.&lt;/p&gt;
&lt;p&gt;Luckily, by way of a semi-random click on a search link, I&amp;rsquo;ve found the following description
from &lt;a href=&#34;https://developers.cloudflare.com/pages/how-to/refactor-a-worker-to-pages-functions/&#34;&gt;a refactoring how-to&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this guide, you will learn how to refactor a Worker made to intake form submissions to a Pages
Function that can be hosted on your Cloudflare Pages application. &lt;a href=&#34;https://developers.cloudflare.com/pages/platform/functions/&#34;&gt;Pages Functions&lt;/a&gt; is a serverless
function that lives within the same project directory as your application and is deployed with
Cloudflare Pages. It enables you to run server-side code that adds dynamic functionality without
running a dedicated server. You may want to refactor a Worker to a Pages Function for one of these
reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you manage a serverless function that your Pages application
depends on and wish to ship the logic without managing a Worker as a
separate service.&lt;/li&gt;
&lt;li&gt;If you are migrating your Worker to Pages Functions and want to use
the routing and middleware capabilities of Pages Functions.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;So that&amp;rsquo;s the summary I believe I was looking for. Before Pages Functions, I&amp;rsquo;d have to manage
either the Workers service for both frontend and backend functionality, or both a Workers and a Pages service, but now I can have just a
Pages service and ship server-side code that the Pages frontend code can use.&lt;/p&gt;
&lt;h2 id=&#34;sharing-document-changes-between-clients&#34;&gt;Sharing document changes between clients&lt;/h2&gt;
&lt;p&gt;So we&amp;rsquo;ll use Pages and Functions to serve the frontend and backend functionality, but now the
question is: where do we store the automerge data?&lt;/p&gt;
&lt;p&gt;Looking at the &lt;a href=&#34;https://www.cloudflare.com/developer-platform/products/&#34;&gt;developer platform products&lt;/a&gt;, it looks like we should use either Workers KV, or
Durable Objects.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;https://www.cloudflare.com/products/workers-kv/&#34;&gt;Workers KV frontpage&lt;/a&gt;, we&amp;rsquo;ve got the following description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Eventually consistent by design, KV caches data globally and is ideal for reference data or
assets that don&amp;rsquo;t change frequently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;Reference data or assets that don&#39;t change frequently&lt;/code&gt; doesn&amp;rsquo;t sound &lt;em&gt;quite&lt;/em&gt; like what we&amp;rsquo;re
going for, since changes &lt;span class=&#34;underline&#34;&gt;could&lt;/span&gt;, theoretically, occur frequently.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;a href=&#34;https://www.cloudflare.com/products/durable-objects/&#34;&gt;Durable Objects&lt;/a&gt; has the following to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Collaborative apps, like chat rooms, games, or whiteboards, require strong consistency of state
to ensure everybody is working with the most up to date version. Durable Objects enables you to
build and run stateful applications on Cloudflare’s global network.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which both sounds exactly like what we need, and also matches with what the chat demo for
Workers referenced above uses.&lt;/p&gt;
&lt;h2 id=&#34;synthesis&#34;&gt;Synthesis&lt;/h2&gt;
&lt;p&gt;So from all of this, it sounds like our Cloudflare stack will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pages, for the frontend functionality&lt;/li&gt;
&lt;li&gt;Pages Functions, for the backend/durability functionality&lt;/li&gt;
&lt;li&gt;Durable Objects, for the data synchronization between clients&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;next-up&#34;&gt;Next up&lt;/h2&gt;
&lt;p&gt;Now that we know the foundational infrastructure tech we&amp;rsquo;re going to use, we can layer on top of
that by exploring one of the following (or even something I haven&amp;rsquo;t foreseen yet):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How Pages Functions work, specifically, so we can understand how we tie the frontend and
backend together.&lt;/li&gt;
&lt;li&gt;How to deploy a basic CLJS app &amp;ndash; frontend only &amp;ndash; to Pages&lt;/li&gt;
&lt;li&gt;How to add basic backend CLJS capabilities via Pages Functions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See you next time!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>AutoFlare Overview</title>
      <link>https://justenough.software/posts/serverless-automerge/</link>
      <pubDate>Thu, 20 Jul 2023 13:38:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/serverless-automerge/</guid>
      <description>I&amp;rsquo;ve got a project idea, which I&amp;rsquo;ve just now decided to call AutoFlare, that I&amp;rsquo;ve been rolling around in my head, primarily as a way to learn more about three technologies:
Cloudflare&amp;rsquo;s cloud offerings Fulcro automerge CRDT I&amp;rsquo;ve got a lot of experience with AWS and GCP, and there are plenty of things I like about those platforms, but I&amp;rsquo;d like to branch out, and some of the blog posts I&amp;rsquo;ve seen from Cloudflare around network egress costs and things has got me curious.</description>
      <content>&lt;p&gt;I&amp;rsquo;ve got a project idea, which I&amp;rsquo;ve just now decided to call &lt;code&gt;AutoFlare&lt;/code&gt;, that I&amp;rsquo;ve been rolling
around in my head, primarily as a way to learn more about three technologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cloudflare.com/developer-platform/products/&#34;&gt;Cloudflare&amp;rsquo;s cloud offerings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://fulcro.fulcrologic.com/&#34;&gt;Fulcro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://automerge.org/&#34;&gt;automerge CRDT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve got a lot of experience with AWS and GCP, and there are plenty of things I like about those
platforms, but I&amp;rsquo;d like to branch out, and some of the blog posts I&amp;rsquo;ve seen from Cloudflare
around network egress costs and things has got me curious. I&amp;rsquo;d like to learn more about their
various offerings, and play around with building a mildly complex application with just what
they&amp;rsquo;ve got. (This blog is hosted by Cloudflare, as a static set of assets, which I&amp;rsquo;ve really
enjoyed the simplicity of.)&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got &lt;em&gt;some&lt;/em&gt; experience with Fulcro, and, of all of the web frameworks I&amp;rsquo;ve used, it seems to
be the most cohesively designed, where I don&amp;rsquo;t have to spend a bunch of time choosing and
tweaking routing libraries, or storage solutions, etc. I&amp;rsquo;d like to really stretch my
understanding of Fulcro with an app more complex than just the Fulcro book, thus why it&amp;rsquo;s part of
this experiment.&lt;/p&gt;
&lt;p&gt;As for Automerge CRDT, I&amp;rsquo;ve wanted to explore and learn this library since I first learned about
it. I&amp;rsquo;m really motivated by the idea of building local-first apps, and this library seems like
it&amp;rsquo;s solved a really hard problem related to building a local-first app. Also, I&amp;rsquo;ve got a vague
sense that this might be useful in &lt;del&gt;luring&lt;/del&gt; teaching JS devs about the joys of CLJS development.&lt;/p&gt;
&lt;p&gt;This series of posts will be different forms and formats of exploring these technologies and
building this small project. Posting order will be largely dependent on my whims, and what
strikes me as the most interesting thing to look at in the moment.&lt;/p&gt;
&lt;p&gt;See you in the next post!&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Hello World</title>
      <link>https://justenough.software/posts/hello-world/</link>
      <pubDate>Mon, 26 Jun 2023 13:37:00 -0500</pubDate>
      
      <guid>https://justenough.software/posts/hello-world/</guid>
      <description>I hope to fill this blog with various explorations and musings.</description>
      <content>&lt;p&gt;I hope to fill this blog with various explorations and musings.&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
