Studying Diffuse - A Cloud Music App
2023-10-29
#study-session
Source Code Study of
Why I chose this?
First of all whenever I learn a new language I want to learn from an example. I also like the example to be somewhat related to multimedia or creative domains, in this case music streaming. It also showcased an interesting architecture of a clear frontend and backend, in Elm which was the language in question. I want to learn Elm as a purely functional alternative Frontend language to Javascript, so this looked like the perfect fit.
Environment
What caught my attention?
The environment is featuring multiple programming languages: js, elm, haskell
each with their own dependencies and package managers: npm, cabal, stack
And an unfamiliar new system, which I came across before: 'nix'
I was wondering how everything played together.
What is going on technically?
Nix is a reproducible build system. Having a look at the shell script located in nex/shell, we can see that it defines entire toolchains and languages, or rather language package managers. The building itself is done through Just, which looks very interesting, having a minimal definition for the different build tasks, which can also be expressed in each language natively. Very cool. Nix is additionally run inside a Docker container -> Making use of NixOS?
What is the effect ?
The effect is a purely functional and compact system that builds and manages your dependencies automatically.
What else supports this effect?
The interaction with Just makes this very powerful. First nix downloads the packages and sets up the dev environment and then runs Just which in turn supports multiple building instructions to build the different parts of the system and runs additional tasks.
How can I use this?
Get Nix, and use it in multi-language tools, however it is only supported through WSL on Windows.
However Just could be an interesting alternative to Gulp, especially in polyglot projects.
Architecture
What caught my attention?
- The Elm code is organized into Applications and Library. Applications is Brain and UI and higher-ordered the source code divided into Library and Application. I really appreciate the clear separation.
- The module "Brain", could it be a Backend implemented in Elm, is that possible?
- The module "UI" is built as Browser.application with a lot of URL handling and Subscriptions
What is going on technically?
Library contains small Snippets for ... to serve into UI and Brain:
- Cryptography.HMac hashing for Cloud providers (Sources.Services.AmazonS3, Sources.Services.Azure)
- Dict.Ext some extension for Dictionaries (used everywhere where quick Data access is needed)
- Html.Ext some extension for HTML (used in view and Notifications for handling tapping behavior)
- Http.Ext some extension to HTTP (mainly used to Responde to Dropbox responses)
- Json.Decode.Ext some extension to JSON decoding (used in various areas for more robust error handling of parsing)
- Lens.Ext some extension to Monocle.Lens (way to handle changing values of very complex immutable data structures)
- List.Ext some extension to Lists (various functions to do some more complex list manipulation in State handling of UI)
- Maybe.Ext some extension to Maybe (implements abstractions around Maybe.Extra used in Queue to adjust naming to semantics)
- Same is done with Return, String, Task, Time
- Playlists which defines a playlist type and decoding and matching functionality
I was right, Brain seems to be a
backendworker. This architecture reminds me of electronjs. It uses Platform.worker as entrypoint and has no "view" (obviously). It uses the Alien abstraction to communicate with the UI application. Brain seems to be running in the background taking care of heavy asynchronous tasks, like downloading and connecting to Service providers. Every submodule is organized into a Types definition which contains its own definition of Msg and State defining its own update function. This is done for:- User
- Task
- Tracks
- Sources
The Module UI seems to be a typicial single page web app with URL handling. It uses Browser.application as entry point.
What is the effect ?
- Can extend libraries and define building blocks to be reused. It is also portable decoupling the main concepts from their applications.
What else supports this effect?
- When using most of the extensions the original Module and its Extension are imported into the same name space, allowing for a modular and cohesive workflow.
How can I use this?
Library or Framework
What caught my attention?
- The few Haskell modules found in "Build" make use of Something called "Shikensu" for building appearently.
- Css is implemented with Tailwind.
- There is also a strange Elm review system.
- On the Elm side a library or framework stood out because of its name: Alien.
- elm-monocle
What is going on technically?
- Shikensu: Run a sequence of functions on in-memory representations of files
- Tailwind Settings are defined with a JS file
- Elm Config seems to be a list of rules which are imported from user created libraries which test the code for certain specs (
elm-review
analyzes your source code, trying to recognize code that is known to cause problems. All the rules describing problematic code are written in Elm, andelm-review
does not come with built-in rules; instead users are encouraged to write rules themselves and publish them as Elm packages, for everyone to benefit) - Alien: nvm, not a library/framework, a custom abstraction (check abstractions), also interesting all the modularized code sits in a separate Folder called "Library" (check architecture) This involves the incoming and outgoing data. Including the communication between the different Elm apps/workers.
What is the effect ?
- Shikensu is used somehow to write some meta-data to the build process. My best guess is from a quick glance, that the built files are modified by Shikensu after they have been written without really opening them. It is also aware of the file-tree which is processed before writing.
- Very elegant Definition of styling through javascript which is then compiled to CSS
What else supports this effect?
- It works by invoking
stack build
in the Justfile @system definition, first building then executing, which is called in every build task and system related task. This also seems to be related to the following licensing step. Maybe licensing is injected in each file? - There are additional plain CSS Files which import the Tailwind modules for each Region or Component of the frontend, making it modular and as it seems have to write little code.
- A rich ecosystem of user made rule definitions can help with customization a lot
How can I use this?
- Generally speaking I like this very colorful ecosystem of different languages and build steps being all combined neatly into one Task runner, without having to stick to a common Interface like in GulpJS with streams. It seems elegant and very scalable, yet flexible. Haskell as pipeline tool seems to be very intruiging!
- I think Tailwind could be a neat option for CSS and Javascript interoperability, like when defining colors and other style related data. Both could feed from the same source ensuring a cohesive look and reducing repetitions.
- When I am going to code in Elm I can use elm-review to enforce some more coding Quality and catch some errors before they happen
Abstraction
What caught my attention?
- The Alien abstraction in the Elm Library, because of its unorthodox name, yet expressing a concept concisely: Interfacing with external systems. Or communicating between alien worlds.
- Playlist type
- Track and derivate types
- Sources type
- Alfred?
- Brain.Msg
What is going on technically?
What is the effect ?
What else supports this effect?
How can I use this?
Interesting Algorithm
What caught my attention?
- List.Ext :: move function
What is going on technically?
What is the effect ?
What else supports this effect?
How can I use this?
Syntax
What caught my attention?
- The use of the "|>" which reminded me of imperative statement lists or the Haskell do notation
- The keyword "port"
What is going on technically?
What is the effect ?
What else supports this effect?
How can I use this?