<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Simon Pantzare</title>
    <description>The latest articles on DEV Community by Simon Pantzare (@pilt).</description>
    <link>https://dev.to/pilt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F569353%2F28370142-88f2-4a59-9afc-bab8ac0b65f6.jpeg</url>
      <title>DEV Community: Simon Pantzare</title>
      <link>https://dev.to/pilt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pilt"/>
    <language>en</language>
    <item>
      <title>DuckDB: Simplifying data analytics for happier data professionals and reduced hosting costs</title>
      <dc:creator>Simon Pantzare</dc:creator>
      <pubDate>Mon, 24 Apr 2023 07:38:47 +0000</pubDate>
      <link>https://dev.to/pilt/duckdb-simplifying-data-analytics-for-happier-data-professionals-and-reduced-hosting-costs-2o44</link>
      <guid>https://dev.to/pilt/duckdb-simplifying-data-analytics-for-happier-data-professionals-and-reduced-hosting-costs-2o44</guid>
      <description>&lt;p&gt;The world of data analytics is dominated by large platforms that only sometimes offer the flexibility of using your own hardware. When possible, it's often meant to run on clusters, not your laptop.&lt;/p&gt;

&lt;p&gt;Enter DuckDB, an in-process database management system perfect for analytics while keeping your favorite tools and hardware in play. No more waiting for jobs to complete on remote clusters! Plus, it scales well beyond the needs of many organizations, even on a tight budget.&lt;/p&gt;

&lt;p&gt;Intrigued, I tested DuckDB with a 107 GB, 5 billion row dataset of Parquet files, a standard data lake format, and looked into what it could mean for hosting bills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fet.dev/posts/duckdb-means-happy-data-folks"&gt;DuckDB lets data folks use familiar tools on their own computers which means they stay happy and efficient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fet.dev/posts/throwing-lots-of-data-on-duckdb"&gt;Throwing 107 GB and 5 billion fake rows of order data at DuckDB and Athena&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fet.dev/posts/costs-of-analytics-on-dedicated-hardware-vs-aws"&gt;Costs to run analytics on dedicated servers compared to AWS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DuckDB offers an enticing alternative for those seeking a more flexible and cost-effective data analytics solution. Give it a try and see the difference it can make for your organization!&lt;/p&gt;

</description>
      <category>database</category>
      <category>analytics</category>
      <category>duckdb</category>
    </item>
    <item>
      <title>ClojureScript on Cloudflare Workers</title>
      <dc:creator>Simon Pantzare</dc:creator>
      <pubDate>Sun, 18 Apr 2021 19:36:05 +0000</pubDate>
      <link>https://dev.to/pilt/clojurescript-on-cloudflare-workers-2d9g</link>
      <guid>https://dev.to/pilt/clojurescript-on-cloudflare-workers-2d9g</guid>
      <description>&lt;p&gt;I am a long-time user of AWS. Lambda is great, but for many use cases I feel like it brings too much complexity. You need to be aware of the surrounding AWS landscape and how Lambda ties into IAM, CloudWatch Events if you run cron-like jobs or API Gateway if you want to expose HTTP endpoints. Serverless framework and similar make things easier by hiding details. The hoops you need to go through to avoid cold starts are annoying.&lt;/p&gt;

&lt;p&gt;I am yet to use Cloudflare Workers professionally and can't speak to how the service fares in practice but I'm excited by the operational simplicity it promises. I'm not using Durable Objects in this post but access to persistent memory in V8 isolates at edge nodes seems like a strong approach to scale out web services. It seems like you could avoid introducing many cache layers commonly found in web services. &lt;/p&gt;

&lt;p&gt;Clojure I'm just fascinated by. I've been keeping tabs on it but have never done anything substantial with it. I have worked mostly in statically typed languages over the last years in code bases that follow an imperative style. While I appreciate types and compile-time errors and how these things bring at least some level of structure to any pile of code, there seems to be a sweet-spot where, if you can keep things simple enough, the type system adds more overhead than it brings clarity. I also appreciate that in Clojure, immutability is something that you need to actively opt out of.&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project setup and worker source
&lt;/h2&gt;

&lt;p&gt;First, we create an empty npm project that depends on &lt;a href="https://github.com/thheller/shadow-cljs"&gt;shadow-cljs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir lispmachine &amp;amp;&amp;amp; cd $_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lispmachine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shadow-cljs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.12.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shadow-cljs compile worker"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;shadow-cljs.edn&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{:source-paths ["src/main"]
 :dependencies []
 :builds       {:worker {:target     :esm
                         :output-dir "dist"
                         :modules    {:worker {:exports {default lispmachine.worker/eventHandlers}
                                               }}}}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add our worker code. &lt;code&gt;src/main/lispmachine/worker.cljs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lispmachine.worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eventHandlers&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:fetch&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;js/Response.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Clojure &amp;lt;3 Cloudflare Workers!\n\n"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;js/JSON.stringify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should be able to compile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cloudflare Workers setup
&lt;/h2&gt;

&lt;p&gt;Next, install and configure &lt;a href="https://github.com/cloudflare/wrangler"&gt;Wrangler&lt;/a&gt; if you haven't already.&lt;/p&gt;

&lt;p&gt;You need to be on 1.16.0 or later with support for ES modules. For now, to use ES modules on Workers you also need to &lt;a href="https://developers.cloudflare.com/workers/cli-wrangler/configuration#es-modules"&gt;opt-in to the Durable Objects open beta&lt;/a&gt;. (You can avoid ES modules and add a bundler but I didn't want that extra step. If you do, &lt;a href="https://github.com/evanw/esbuild"&gt;esbuild&lt;/a&gt; will do the trick.)&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;wrangler.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"lispmachine"&lt;/span&gt;
&lt;span class="py"&gt;workers_dev&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"javascript"&lt;/span&gt;

&lt;span class="nn"&gt;[build]&lt;/span&gt;
&lt;span class="py"&gt;cwd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./dist"&lt;/span&gt;
&lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npm run build"&lt;/span&gt;
&lt;span class="py"&gt;upload.format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"modules"&lt;/span&gt;
&lt;span class="py"&gt;upload.main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"worker.js"&lt;/span&gt;
&lt;span class="py"&gt;upload.rules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="err"&gt;type&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ESModule"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;globs&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["**/*.js"]&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had to add &lt;code&gt;upload.rules&lt;/code&gt; because shadow-cljs generates files with &lt;code&gt;.js&lt;/code&gt; extensions and Wrangler assumes such files are CommonJS. I also had to use &lt;code&gt;cwd = "./dist"&lt;/code&gt; after getting errors about the main module not being found with &lt;code&gt;upload.main = "./dist/worker.js"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we are ready to take this live and see that it works!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CF_ACCOUNT_ID=... wrangler publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://lispmachine.yoursubdomain.workers.dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Clojure &amp;lt;3 Cloudflare Workers!

{"fetcher":{},"redirect":"manual","headers":{},"url":"https://lispmachine.yoursubdomain.workers.dev/","method":"GET","bodyUsed":false,"body":null}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(If anyone knows why &lt;a href="https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties"&gt;&lt;code&gt;request.cf&lt;/code&gt;&lt;/a&gt; isn't part of the output from &lt;code&gt;(js/JSON.stringify request)&lt;/code&gt; please let me know.)&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>cloudflare</category>
      <category>clojurescript</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
