This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-05-09
Channels
- # announcements (23)
- # babashka (7)
- # beginners (69)
- # biff (5)
- # calva (12)
- # cider (10)
- # cljfx (9)
- # clojure (60)
- # clojure-austin (1)
- # clojure-europe (14)
- # clojure-korea (2)
- # clojure-losangeles (2)
- # clojure-madison (1)
- # clojure-nl (1)
- # clojure-norway (23)
- # clojure-uk (7)
- # clojuredesign-podcast (16)
- # clojurescript (40)
- # datomic (8)
- # gratitude (4)
- # mount (3)
- # nrepl (2)
- # off-topic (38)
- # pathom (3)
- # releases (1)
- # ring (8)
- # shadow-cljs (7)
Have you felt lost in a new codebase? How can you make sense of it quickly? What clues show how it all fits together? In our latest episode, we look for a suitable place to dig into the code and find an entry point. https://clojuredesign.club/episode/115-the-main-event/
The codebase at my workplace is huge: it's a Java desktop application (and a bunch of corba servers) that lets meteorologists see all kinds of weather data and, for the parts I work on, actually draw and edit representations of that data (e.g an area of high winds represented as a polygon with some data and metadata attributes). It's been around for decades, so it's age coupled with its sheer size means that anytime you need to poke around an area you haven't been in for a while, you pay the "servlet tax" of entry points (each "layer" -- think Photoshop layers -- deals in one kind of data and is dynamically initialized, wired, and dispatched to by the core frameworks) along with the in-house technology tax (e.g our configuration framework is kind of jaxb but not, because it predates it). Add to that some layers/sub components using a DI fwk in the typical (over the top imo) Java way, and you have a very nebulous starting point that's pretty much impossible to understand unless you're very comfortable using a debugger to build your mental model of various workflows. And God help you if someone distracts you before your carefully constructed, house of cards mental model crystallizes into something useful. Luckily, I'm very good at guessing where things are and have a very good memory, because otherwise, I could imagine losing hours on the regular to fruitless treasure hunts
On the subject of DI, am I inferring correctly that you both prefer "chunkier" components that are wired together at the top level? What I notice tends to be popular, at least in Java/C# land (maybe oop in general?) is fine-grained writing where every single dependency of every single object is handled by the DI fwk/component system. Especially with Java, this becomes a mystery box quickly because you're navigating interfaces and impls and looking for magic annotations that put things together; there's no explicit place where you see at a glance that A concretely depends on B. I get the feeling that the intended usage of Integrant is more like this than Component is, where you have a map that says the router has these handlers and these handlers have these deps (by key) and these deps have the database (by key) and the database has this config, and... Like, sure, maybe the map is a picture of the system, but it's huge and you're doing the https://en.m.wikipedia.org/wiki/Dem_Bones everytime you need to understand the system. Still better than magic annotations I suppose
@U04RG9F8UJZ Oh, the layers! So hard to reason about! In my experience, stratification happens because developers want to "separate concerns", which is a good goal, but the way it all gets wired together makes it really hard to understand how they all interact with each other. In my mind, the "the bringing the concerns together" part is at least as important as the separating them! How they all interact with each other should be clear too.
I agree that the finer the components/dependencies, the harder it is to work with them. I love how you put it! "A mystery box!" Indeed! I'd love to share more specifics on my approach. I suspect I'm going to need to create some example code. Oh, to have more time!
To clarify, when I mentioned layers I didn't mean it in the sense of technical stratification, but in the "overlapping things" sense of Photoshop. Each "layer" in our application is essentially it's own "sub app" that provides a full set of features: it's own data model, it's own view/display configuration, it's own mouse event handling, etc. While each of these pieces is, at its core, an MVC that plugs into an overarching set of frameworks, your point on stratification definitely stands: it would be impossible to have only the MVC classes because they'd be doing too much, and so now each "sub app" is it's own little universe of software design: how does it load data? How does it render? Are there specific DTOs? Is there validation on user interactions? And so on and so on. It's kind of like how every snowflake is made of water around some nucleus, so finding your way around a new snowflake's twists and turns and fractals shouldn't be a problem 😉
I'm definitely excited to see (or at least hear) more about how you organize your applications. Some insight in right-sizing components would be helpful and pretty broadly applicable, I think. One challenge with trying to find code examples is they often stand alone, without someone talking through them and giving general pointers or commentary. They also are either too large (because they're a real project, and without taking a lot of time to build up the context, it's hard to grok) or too small (because it's a toy to show off the fwk, and honestly you'd probably not even really bother with a component fwk for a project that size)
UIs are hard. The OO model for UIs made so much sense to me, but became intractable as my UIs got larger. State management because a huge problem! The state is spread across all the UI components. React, but more generally a functional approach, has helped me so much. I can just generate a UI description from data.
I love that overall approach: generate the new version from the data and reconcile the old version and the new version to figure out the changes that must be made. It's a good model that works for a lot more things than just UI programming.
Finding great examples is hard. I related to the "too small" and "too big" problem you mention. I keep thinking that I need to create some kind of public project I can use for illustration and make it the "just right" size.
I feel very pressed for time, but I think if I work on that a little at a time, I could probably use that codebase for all sorts of illustrations.
Re: GUIs and the React approach, definitely had the same experience. We went with mvvm on one of the newer projects because the framework (javafx) really wants mutation (like swing before it), but that's a pain in the butt to work with in an event driven system where events are flowing both from the user interacting with it and from the network as a result of other users interacting with their own views. The mvvm separation let us keep an immutable model and bind the view to a (mutable) view model we updated in response to the central source of truth changing. Before making that switch, we had a GUI that responded to events directly and hit exactly that problem of distributed truth: the truth was the event stream, but now every GUI component became it's own cache of event aggregation for the events it cared about (cache because of the mutable models attached to each GUI component). If anything got out of sync, screwed
> I keep thinking that I need to create some kind of public project I can use for illustration and make it the "just right" size. That would be awesome! A long time ago, I tried to implement the twitter app from episodes 6-11: https://github.com/jumarko/functional-design-in-clojure/tree/master/twitter But it can be quite far from what you imagined - having a canonical version of these would be very useful...
@U04RG9F8UJZ Yes! Making the immutable model the single source of truth simplifies so many things.
@U06BE1L6T Oh cool! Thanks for sharing that!