HackerTrans
TopNewTrendsCommentsPastAskShowJobs

codemonkey-zeta

641 karmajoined 6 tahun yang lalu

Submissions

A Datomic entity browser for prod [video]

youtube.com
4 points·by codemonkey-zeta·6 bulan yang lalu·1 comments

comments

codemonkey-zeta
·5 hari yang lalu·discuss
The maps haven't changed at all, this is a feature at destructuring sites.
codemonkey-zeta
·19 hari yang lalu·discuss
> The mess just moves

That's exactly the point. The author recognizes that people will extract components, and that is exactly why tailwind is attractive.

Plain CSS offers a componentization layer over (mostly) classes, but modern SPA frameworks offer their own componentization layers over functions. It's annoying and error-prone to keep these 2 layers, and lots of devs just abandon CSS for utility class mess. It's just a different choice.
codemonkey-zeta
·26 hari yang lalu·discuss
I like the framing of organizational slack as immune system, instead of fat, and I emphatically agree with the author.

> ...“slack”: unbooked time that isn’t already spoken for. It’s always the first casualty, because it’s treated as a nicety... because it looks like waste...

> But that’s not what slack is. Slack is the only reason anything that comes up ever gets acted on. It’s what lets people take that signal that something is wrong, figure out why it’s happening, and then solve it... Without slack, the signal still arrives, everybody’s just too busy to pick up the phone or listen to the backlog of voicemails.

> [The AI playbook] gets this infuriatingly backwards: it treats slack as the thing AI lets you eliminate. If the tools make us faster, why do we still need buffer time?

> Getting rid of it at the time you’re flooding the system with machine-generated code you don’t fully understand removes the mechanism to absorb something we know will happen: it will surprise you.

> You didn’t cut fat. It was never fat. You cut your organization’s immune system.
codemonkey-zeta
·27 hari yang lalu·discuss
Nope, splitting green wood is much more difficult than splitting dried logs, so I often cut a tree in the spring, stack the rounds, then split those rounds in the fall.

People overestimate how dry wood needs to be to burn correctly. Just have some ultra-dry kindling (seasoned for 2+ years) and you won't have any problems.

On the contrary, I know some folks who let all their wood dry too far, and it burned way too hot and ruined their stove (and almost burned their house down).
codemonkey-zeta
·4 bulan yang lalu·discuss
> for reasons that nobody can articulate

This is only true if you ignore the role of America's greatest ally, in which case, the motivations become very obvious.
codemonkey-zeta
·5 bulan yang lalu·discuss
You assume the stone is released along a circular path, but that isn't quite right. When you release the stone you extend your arm forward, changing the arc of travel.
codemonkey-zeta
·5 bulan yang lalu·discuss
Nice blog! However, when I hear timeline, I want to see a timeline. This is an article ordered by time, which is much less interesting, and very long.
codemonkey-zeta
·6 bulan yang lalu·discuss
I'm a big fan of Dustin, I think the programming interface electric presents is very compelling, and the benefits are really impressive.

The killer feature, for me, of electric is that it makes the network _transparent_ to me, the programmer, and makes solving complex problems concise.

I see electric as a kind of emacs - an excellent operating system that lacks a decent front-end. Reactive programming is hard, and it really ought to be way more visual, and electric should give me those tools.

I find the frontend side of the electric somewhat obtuse, and it's easy to go off the rails, needing to understand the underlying reactive layer https://github.com/leonoel/missionary. Why should I target this bizarre DSL when there are millions of React, Angular, JQuery apps out there that work, and would be too onerous to adapt to this style of programming, and too annoying to carry a second framework in prod (even if you bundle an electric app in your existing one, the runtime can be very big by web standards). I would love to see a framework built on top of electric that interfaces with any existing frontend as easily as it does now for any backend (Datomic is just one target of many for the spreadsheet Dustin built). I may try to explore this idea myself.

But is the business of Hyperfiddle building instances of this new hypermedia, or the hypermedia system itself? I don't understand exactly what Dustin is selling me, at the end. Trying to sell this particular spreadsheet as a solution, or is it access to the runtime (electric 3)? How am I supposed to buy into a new programming model if I cannot use it?
codemonkey-zeta
·6 bulan yang lalu·discuss
I find that Lisps encourage this behavior more than other languages. Many (most?) of the lisp functions I read have the exact same structure:

  (fn some-function [args]
    (let [binding (transform args)]
      (an-expression binding)))
I find that this makes skimming lisp code much easier, because I can usually skip reading the bindings and just read the function name and ultimate expression and usually get the gist very quickly.

You might wonder how this is different than the example you provided, and the answer is because you could sneakily intersperse anything you wanted between your imperative bindings (like a conditional return statement), so I actually have to read every line of your code, vs in a lisp `let` I know for a fact there is nothing sneaky going on.
codemonkey-zeta
·6 bulan yang lalu·discuss
deps.edn is becoming the default choice, yes. I interpreted the parent comment as saying "you will see advice to use leiningen (even though newer solutions exist, simply because it _was_ the default choice when the articles were written)"
codemonkey-zeta
·7 bulan yang lalu·discuss
Can you describe how rsc allows you to avoid rest endpoints? Are you just putting your rsc server directly on top of your database?
codemonkey-zeta
·7 bulan yang lalu·discuss
Except it wasn't $12B to farmers. Farmers have been squeezed by monopolies on both the supplier (seed, equipment, etc) side AND the buyer side (there is often only a single buyer of grain in an area, for example) to the point that most large scale American farms are struggling to make any profit, and service their sizeable debts. The $12B will immediately be transferred to these monopolies, it will not go to farmers.
codemonkey-zeta
·8 bulan yang lalu·discuss
This is a great place to start! https://clojure.org/about/history
codemonkey-zeta
·8 bulan yang lalu·discuss
To be clear, there's nothing wrong with your approach, and many people implement systems exactly the way you are describing in Clojure using Records (which are Java classes).

  (defrecord UserLoginView [email password])

  ;; DIFFERENCE: compile-time validation
  (defn login [^UserLoginView view]
    (authenticate (:email view) (:password view)))

  ;; Usage
  (let [user-data {:user/email "[email protected]"
                   :user/password-hash "hash123"
                   :user/address "123 Main St"
                   :user/purchase-history []}

        ;; DIFFERENCE: construct the intermediary data structure - ignore extra stuff explicitly
        login-view (->UserLoginView
                     (:user/email user-data)
                     (:user/password-hash user-data))]
    (login login-view))


I prefer not to work this way though. The spec-driven alternative could be:

  (require '[clojure.spec.alpha :as s])
  (require '[clojure.spec.gen.alpha :as gen])

  (s/def :user.login/email string?)
  (s/def :user.login/password-hash string?)
  (s/def :user.login/credentials
     (s/keys :req [:user.login/email ;; spec's compose
                   :user.login/password-hash]))

  (defn login [credentials]
    ;; DIFFERENCE: runtime validation
    {:pre [(s/valid? :user.login/credentials credentials)]}
    (authenticate (:user.login/email credentials)
                  (:user.login/password-hash credentials)))

  (let [user-data {:user.login/email "[email protected]"
                   :user.login/password-hash "hash123"
                   :user/address "123 Main St"  
                   :user/purchase-history []}]
    ;; DIFFERENCE: extra data ignored implicitly
    (login user-data))

  ;; Can also pass a minimal map
  (login {:user.login/email "[email protected]"
          :user.login/password-hash "hash123"})

  ;; or you can generate the data (only possible because spec is a runtime construct)
  (let [user-data 
        (gen/generate (s/gen :user.login/credentials)) ; evaluates to #:user.login{:email "cWC1t3", :password-hash "Ok85cHMP5Bhrd4Lzx"}
        ]
    (login user-data))

The drawbacks of Records are the same for Objects - Records couple data structure to behavior (they're Java classes with methods), while spec separates validation from data, giving you:

- generative testing (with clojure.spec.gen.alpha/generate)

  You say "it makes sense to unit test logins using every conceivable variation of `UserLoginView`", well, with spec you can actually *do that*:

  (require '[clojure.test.check.properties :as prop])
  (require '[clojure.test.check.clojure-test :refer [defspec]])

  (defspec login-always-returns-session 100
    (prop/for-all [creds (s/gen :user.login/credentials)]
      (let [result (login creds)]
        (s/valid? :user.session/token result))))

  This is impossible with Records/Objects - you can't generate arbitrary Record instances without custom generators.
- function instrumentation (with clojure.spec.test.alpha/instrument)

- automatic failure case minimization (with clojure.spec.alpha/explain + explain-data)

- data normalization / coercion (with clojure.spec.alpha/conform)

- easier refactoring - You can change specs without changing data structures

- serialization is free - maps already serialize, whereas you have to implement it with Records.

Plus you get to leverage the million other functions that already work on maps, because they are the fundamental data structure in Clojure. You just don't have to create the intermediate record, let your data be data.
codemonkey-zeta
·8 bulan yang lalu·discuss
> you trade away your ability to make structural guarantees about which functions depend on which fields

You might make this trade off using map keys like strings or keywords, but not if you use namespace qualified keywords like ::my-namespace/id, in combination with something like spec.alpha or malli, in which case you can easily make those structural guarantees in a way that is more expressive than an ordinary type system.
codemonkey-zeta
·8 bulan yang lalu·discuss
Author is on the verge of having a Clojure epiphany.

> 1. You should often be using different objects in different contexts.

This is because "data" are just "facts" that your application has observed. Different facts are relevant in different circumstances. The User class in my application may be very similar to the User class in your application, they may even have identical "login" implementations, but neither captures the "essence" of a "User", because the set of facts one could observe about Users is unbounded, and combinatorially explosive. This holds for subsets of facts as well. Maybe our login method only cares about a User's email address and password, but to support all the other stuff in our app, we have to either: 1. Pass along every piece of data and behavior the entire app specifies 2. Create another data object that captures only the facts that login cares about (e.g. a LoginPayload object, or a LoginUser object, Credential object, etc.)

Option 1 is a nightmare because refactoring requires taking into consideration ALL usages of the object, regardless of whether or not the changes are relevant to the caller. Option 2 sucks because your Object hierarchy is combinatorial on the number of distinct _callers_. That's why it is so hard to refactor large systems programmed in this style.

> 3. The classes get huge and painful.

The author observed the combinatorial explosion of facts!

If you have a rich information landscape that is relevant to your application, you are going to have a bad time if you try modeling it with Data Objects. Full stop.

See Rich Hickey's talks, but in particular this section about the shortcomings of data objects compared to plain data structures (maps in this case).

https://www.youtube.com/watch?v=aSEQfqNYNAc
codemonkey-zeta
·10 bulan yang lalu·discuss
The absolute best resource I've found for educating myself about this topic is John Vervaeke's free online course "Awakening from the meaning crisis". You can search it in YouTube or Spotify.

He explains in detail exactly why a "nostalgic return to religion" cannot save us from, not just nihilism, but the entire set of crises western society is undergoing.
codemonkey-zeta
·10 bulan yang lalu·discuss
I think the surface area for bugs in a C++ dependency is way bigger than a JS one. Pulling in a new node module is not going to segfault my app, for example.
codemonkey-zeta
·10 bulan yang lalu·discuss
I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem. Vendoring can mitigate your immediate exposure, but does not solve this problem.

These attacks may just be the final push I needed to take server rendering (without js) more seriously. The HTMX folks convinced me that I can get REALLY far without any JavaScript, and my apps will probably be faster and less janky anyway.
codemonkey-zeta
·5 tahun yang lalu·discuss
Hands down the best cooking channel on YouTube for me at least.

The thing I most appreciate about Mike's work with Pro Home Cooks is that he shows what _doesn't_ work and what he would do different next time. I find that's the most important skill to hone when learning to cook.

He also does a ton of improvisation during his videos. Things like, "I was going to put broccoli in this but all I had was kale, but I still want a little more substance so maybe I'll make kale chips and roast some cashews too." Creativity in the kitchen is a huge part of the fun, and I haven't seen other cooking education sources that demonstrate it effectively.