Curious (Clojure) Programmer Simplicity matters

Menu

  • Home
  • Archives
  • Tags
  • About
  • My Talks
  • Clojure Tip of the Day Screencast
  • (Open) Source
  • Weekly Bits & Pieces
  • RSS

Weekly Bits 03/2022 - Domain Modeling, Finite State Machines, Time Series, Api Security, and Impact Mapping

February 9, 2022
Table of Contents
  • Clojure
    • PF.tv Domain Modeling series
      • 452: Domain Invariants
      • 453: Model as Toy
      • 455: How and when to apply domain modeling
    • Clojure cheatsheet - collections functions: every?, not-every?, not-any?
    • Downloading zip file from an URL via clj-http in Clojure - e.g. Amplitude Export API
      • Apache Commons Compress
  • Coda Hale, Dan McKinley and Finite State Machines (and more)
    • On The Difficulty Of Conjuring Up A Dryad
    • You Can’t Have a Rollback Button
  • AWS & Cloud
    • Audrey Lawrence on Time Series Databases & Amazon Timestream
      • Quick Timestream notes
  • Books
    • Grokking Simplicity (started)
      • Book intro
    • Api Security in Action - HMAC & Timing attacks
    • Practical Monitoring - Basic statistics
    • 50 Quick Ideas to improve your user stories
      • Impact mapping
  • MISC
    • PurePerformance podcast
    • Microsoft Excel highlighting duplicate values & hiding columns

Clojure

PF.tv Domain Modeling series

As in the week before, I’ve been reading through some of the Domain Modeling posts on the PurelyFunctional.tv blog, notably:

452: Domain Invariants

  • domain model consists of information, operations, and invariants

  • some places to encode invariants: types, (property-based) tests, language features, data structures, runtime checks / assertions, documentation, proofs

453: Model as Toy

  • write the model down to spot potential problems - the earlier the better

  • you have a model anyway, it’s just often ad hoc and partially written

455: How and when to apply domain modeling

Erik got a question if he applied domain modeling to a real project.

And he talked about a document signing example:

  • They could do a basic contract signing flow: Create a contract, enter email addresses, and it sends it to everyone to sign.

  • But customers wanted more control:

    • They wanted to say what order people had to sign in.

    • And they wanted other things besides signing, like a review step

  • ⇒ hard to fit these new ideas into the simple model

  • The direct path was just more HTTP endpoints and SQL update statements and a bunch of conditionals

  • But thinking hard brought an idea of state machine (see also Code Hale’s article below)

    • especially the non-determinism allowing parties to sign in different order

  • The (state machine) idea was hard to sell, especially to engineers!

    • but just the process of modeling it with a state machine made them find some quick wins (like separating SQL updates into more atomic actions) which eventually simplified their model/code

Clojure cheatsheet - collections functions: every?, not-every?, not-any?

  • every? (hopefully obvious)

    (every? pos? [1 0 100])
    ;;=> false
    user> (every? pos? [1 10 100])
    ;;=> true
  • not-every? (read "at least one that is not")

    • it’s a complement to every?

    (not-every? pos? [1 0 100])
    ;;=> true
    (not-every? pos? [1 10 100])
    ;;=> false
  • not-any? (read "none")

    • Note: any? is a completely different predicate (it’s not really a collection function - it returns true for any argument, including nil)

    (not-any? pos? [-1 0 -100])
    ;;=> true
    user> (not-any? pos? [-1 0 100])
    ;;=> false

Downloading zip file from an URL via clj-http in Clojure - e.g. Amplitude Export API

I needed to download product analytics data from Amplitude. Amplitude’s Export API generates a zip file that you can download and extract. Here’s a way to download such a file in Clojure:

(defn download-events! [output-file start end]
  (let [{:strs [api-key secret-key]} @api-keys
        response (http/get (format "https://amplitude.com/api/2/export?start=%s&end=%s" start end)
                           {:basic-auth [api-key secret-key]
                            :as :stream})]
    (io/copy (:body response) (io/file output-file))))

(download-events! "all-events-in-january.zip" "20220101T00" "20220131T23")

Here’s a link that may help too: https://stackoverflow.com/questions/32742744/how-to-download-a-file-and-unzip-it-from-memory-in-clojure

Apache Commons Compress

I used this piece of code based on commons-compress library in the past when dealing with compressed files:

(defn- tar-gz-seq
  "A seq of TarArchiveEntry instances on a TarArchiveInputStream."
  [tis]
  (when-let [item (.getNextTarEntry tis)]
    (cons item (lazy-seq (tar-gz-seq tis)))))

(defn- unpack-archive-files
  "Given a .tar.gz unpack it and process every entry via `unpack-file-fn`."
  [compressed-input-stream unpack-file-fn]
  (let [tis (TarArchiveInputStream. (GZIPInputStream. compressed-input-stream))
        tar-seq (tar-gz-seq tis)]
    (doseq [entry tar-seq]
      (unpack-file-fn tis entry))))

Continue reading →

Weekly Bits 02/2022 - Domain Modeling, Java DNS caching, RDS upgrades with Terraform

January 31, 2022
Table of Contents
  • Clojure
    • A few Clojure-related links:
    • PurelyFunctional.tv newsletter - domain modeling series
    • nippy serialization issues with Joda DateTime
  • Java / JVM
    • Regular expressions - character classes
    • Java and DNS caching
      • If you don’t customize it, the default values for caching / TTLS in Java are:
      • networkaddress.cache.ttl and networkaddress.cache.negative.ttl are java security properties:
      • Java calls native function getaddrinfo (on Linux)
  • AWS & Cloud
    • RDS upgrade through terraform - replaced instance, missing tables/data
      • Preparation
      • Prerequisites
      • The surprise
      • Takeaways
    • Cloudonaut - Comparing API Gateways on AWS
  • Books
    • Api Security in Action
    • Practical Monitoring
    • 50 Quick Ideas to improve your user stories
  • MISC
    • Software bill of materials
  • Links

Clojure

A few Clojure-related links:

  • Donut.system: your new favourite component library? (by Daniel Higginbotham)

  • The new Clojure "iteration" function

  • Is there any performance penalty to using vars instead of function references?

    only matters when they’re on a hot path or very fast. If they take microseconds or more to execute I wouldn’t be bothered by it

    — Ben Sless

PurelyFunctional.tv newsletter - domain modeling series

This is not really Clojure-specific, but I started reading through a bunch of posts about domain modeling by Eric Normand (a big FP & Clojure advocate). It starts with PF.tv newsletter # 446 and he’s still publishing new posts.

There’s a lot of great content and insights. My favorite one, so far, has been 447: Domain model fit where he talks about reference back to reality and, as an example, misuse of the Decorator pattern. It also links to two former episodes talking about the Decorator pattern in more detail:

  • 407: two layers of design

  • 412: use and abuse of the decorator pattern

nippy serialization issues with Joda DateTime

We store user session data in Redis via nippy.

After upgrading the library to a newer version, we found a serialization issue in one particular use case:

clojure.lang.ExceptionInfo: Cannot thaw object: `taoensso.nippy/*thaw-serializable-allowlist*` check failed.
This is a security feature.
See `*thaw-serializable-allowlist*` docstring or https://github.com/ptaoussanis/nippy/issues/130 for details!
class-name: "org.joda.time.DateTime"

The solution was to, as they suggest, whitelist all the classes in the org.joda.time package:

  ;; saving joda DateTime instances in the session requires custom allow list for nippy
  ;; see https://github.com/ptaoussanis/nippy/issues/130
  (alter-var-root #'taoensso.nippy/*thaw-serializable-allowlist*
                  (fn [allowlist] (conj allowlist "org.joda.time.*")))

Notice that the default allowlist contains, for example, java.time classes:

*
taoensso.nippy/*thaw-serializable-allowlist*
#{"java.lang.NullPointerException"
...
  "java.time.LocalTime"

See the nippy issue for more details.


Continue reading →

Weekly Bits 01/2022 - analyzing dependencies with clj-kondo, AWS architect mindset, 5 JavaScript features you should learn

January 24, 2022
Table of Contents
  • Clojure
    • <-- macro
    • Analyze dependencies between packages with clj-kondo
  • Emacs
    • restclient
    • Cider debugger
  • AWS & Cloud
    • Cloudonaut - AWS Architect Mindset
    • New blog post about Cloudwatch insights and converting unix timestamps
    • Terraform webinar - tfsec and OPA
    • 10 Rules for better Cloud Security
  • Books update
    • Api Security in Action:
  • Writing
    • AsciiDoc
  • MISC
    • 5 JavaScript features you should learn
    • The Ten Commandments of Egoless Programming
  • Links

Some of the interesting stuff I did, learned or found in the past week.


Continue reading →

AWS Cloudwatch Insights and Unix Timestamps

January 18, 2022

For way too long, I’ve been frustrated by inability of the Cloudwatch Insights UI console to produce human-readable output of latest/earliest functions.

Consider this example: [1]


Continue reading →

Moving My Blog to Cryogen and Cloudflare Pages

January 17, 2022
Table of Contents
  • The Wordpress problem
  • Cryogen
    • Cryogen themes
  • Cloudflare pages
  • The old blog/content
  • AsciiDoc
    • Asciidoc - quick notes and tips
    • Some Asciidoc resources

The Wordpress problem

I wanted to migrate away from the existing Wordpress-based hosting for my curiosprogrammer.net blog for a long time yet I have not found time to do that until now. Today, I’m finally moving towards much simpler approach using Cryogen as the underlying blog engine.


Continue reading →
« Prev Next »

Copyright © 2025 Juraj Martinka

Powered by Cryogen | Free Website Template by Download Website Templates