🔝
2023 CE
Year of respite. Foused on self-awareness and recovery of sanity. Learnt about human body, mind and consciousness. Finished CS50 with an Elixir project and ideated creator apps.
  1. Mar — Simple web in Elixir
    1. Design
    2. Installation
    3. Use
  2. Creator apps
    1. Creators of change
    2. Applications of change
    3. Creative collaboration for creator apps

Mar — Simple web in Elixir

Mar is a simple web framework written in Elixir functional programming language. The design of the library aims to provide a Flask-like experience for Elixir developers. It is a layer of abstraction on top of Plug powered by Bandit.

Design

The design goal for Mar is to make it transparent to the user so someone who just covered the basics of the language can jump right into building a web application. Elixir offers a powerful and aesthetic syntax built-in, such as multi-clause function definitions with parameter pattern matching, module with struct definition, @behaviour and Protocol for polymorphism, and use macro that injects code into the module. Mar attempts to fully utilise these native features to provide a simple and intuitive API for building web applications.

For the user, such brevity means typing in use Mar makes all the connections and sets up reasonable defaults so a web application is defined without an extra file in the lib/. With object-oriented programming, it’s as simple as passing an object. That’s what we see from Flask, Sinatra or Express. The object can encapsulate the state and operation of the application without too much ceremony on the user’s codespace. But for the functional programming paradigm, it usually spills out to the user modules. To manage this, Mar has to keep as much as possible in the library. And it takes accessing the module information of the user code from the library.

I was surprised by the level of frustration such an approach can cause. At first, I thought it was just me who couldn’t come up with an elegant solution right away. But as I dug deeper, I found the trail of lamentation. Most libraries resort to taking some configuration for a module, so the user can manually report to the library. Other than that, the ambition of the community has reached scanning all the modules in the user project and saving them in an ETS or an Agent. I tried it and it was a convoluted, error-prone, and hard-to-maintain solution, at least for my technical capability.

Protocol is an often underappreciated feature of the language. And it sheds light on the problem. Protocols do module consolidation in order to enhance the performance. And the protocol can reach the consolidated modules with __protocol__(:impls). If Mar can slip in protocol implementation code into the user module with use Mar, it will automatically report the module to the protocol. And Mar can access the module without extra configuration. This comes with a nice side effect. Since defimpl takes structs anyway, saving information in the struct is a natural way to keep the module information. And the protocol can work as a liminal codespace instead of being a tool for module registration.

So that’s exactly the way Mar is implemented. Each user module is a unique implementation of Mar.Route. It provides some default defimpl functions and Mar.__using__/1 injects them alongside defstruct handling options. This way, use Mar makes these things possible:

  1. Register the module to the Mar.Route.
  2. Save information in the %MyApp{} struct.
  3. Interact with the library through Mar.Route.MyApp

use Mar takes path and params options. path is the URL path of the route where path parameters are annotated with :. They are parsed and appended to the existing params.

Mar also exports Mar.child_spec/1 so the user can start the supervision tree just by adding Mar as a child. The child spec starts Bandit with Mar.Plug as a general pipeline which goes down to Mar.Router where path-matching, parameter parsing, and action dispatching are done.

Path-matching algorithm is far from optimised. It’s a few iterations over the list of routes. Stream is applied where applicable to alleviate the performance. Once the path finds the module of responsibility, path parameters are parsed to the Plug.Conn first, where they merge over query parameters and body parameters. Then parameters are selectively loaded to the struct. The HTTP method is loaded as well for the action name. Then before the action is dispatched, conn is loaded to the struct. This allows Mar.Route to expose the entire connection to the user module. After the action is dispatched, it exposes the connection once more. And finally, the response gets sent.

Installation

Create a project with supervision tree:

mix new my_app --sup
cd my_app

Add Mar to your dependencies in:

# mix.exs
defp deps do
  [
    {:mar, "~> 0.2.0"}
  ]
end

Add Mar as a child:

# lib/my_app/application.ex
def start(_type, _args) do
  children = [
    Mar
  ]
  # ...
end

Add Mar to your module to make it a route:

# lib/my_app/route.ex
defmodule MyApp.Page do
  use Mar

  def get() do
    "Hello, world!"
  end
end

Spin up a server:

mix run --no-halt
$ curl localhost:4000
Hello, world!

Use

Using Mar makes the module a route. It injects Mar.Route protocol and a struct. Set a path or the default is "/". Add parameters in the path or in the params list.

defmodule MyApp do
  use Mar, path: "/post/:id", params: [:likes, :comment]
end

Name your function after the HTTP method. Take HTTP parameters from a map. Return a response body with text.

def get(%{id: id}) do
  "You are reading #{id}"
end

Returning a map will send a response in JSON.

def post(%{id: id, comment: comment}) do
  %{
    id: id,
    comment: comment
  }
end

Return a tuple to set HTTP status and headers.

def delete(%{id: _id}) do
  # {status, header, body}
  {301, [location: "/"], nil}
end

Mar.Route protocol lets you access Plug.Conn.

defimpl Mar.Route do
  # Mar.Route.MyApp

  def before_action(route) do
    # Access `route.conn` before the actions you have defined.
    route
  end

  def after_action(route) do
    # Access `route.conn` after the actions you have defined.
    route
  end
end

Creator apps

Last summer, I took a retreat at a town in Seoul known for its guesthouses. There were little stores around the corners, unique cafés, and Michelin-confirmed restaurants. The creative vibe of the town gave me a chance to settle down and contemplate.

For years, I’ve been trying to understand the essence of social progress. The history of life, the journey of mankind, the motives of modernisation. I was able to cover the bare minimum to see what and where we are.

But it was difficult to answer as to what I should do at this moment. It’s clear that we should start weaving a social system based on data and creative collaborations, instead of possession and transactions. But what does such a transition take? Can you name one? Am I in the right place to practice it? Or am I just an observer contemplating on what’s possible but can’t be done yet.

One thing that I’ve been practising was app-building. I’ve been learning and curating the most effective ways to build user-facing web apps because I thought that’s the closest thing I can do for the future society. I thought I might systemise a new social network that captures mutual recognition in data, not money.

But the activity of the network still remains as a question. Though I have ideas: creating, crediting, and recognising, they are way too abstract to convey the nuance. If you’ve told a medieval man that commerce and finance would change the world, you would have been laughed at, then executed. There had to be the process of transition such as the Renaissance and the Reformation. And such massive transitions can’t be foreseen until they happen.

The retreat was an escape for me from such an analytical perspective. It was moving to discover the unique projects and their attempts to survive this commercial society. They might have been commodified in a more typical setting. But the locality of the town made all the difference. Each of them had a personality that makes it personal to me as well. I noticed that the charm touches the softer sides of my mind. I was inspired from the human touch.

Then something clicked. I wanted to build apps for the ones who have created the moving experience. As a matter of fact, the personalities behind the projects have changed what an app-building means to me. Ever since then, I have been working on a technical foundation that can serialise such lightweight apps with its unique creative context.

I’ll discuss the technical side in another post. In this one, let’s talk about what I mean by creator apps and how creative collaboration can enable them.

Creators of change

The creator economy has become a thing only after the rise of social media. Namely, creators are content creators and the contents they create fuel the social media.

Is that all? The companies behind the social media often get the spotlight because they are the enablers and they are huge. Indeed, giant platforms such as YouTube, Instagram, or TikTok seem to define what it’s like to live this time.

But I want to bring the focus back to the creators. There’s a fundamental human nature underneath the production and consumption of the creator economy. While social media have innovated the delivery, the point is what is delivered.

And I believe the parcel, the human nature, is change. The creators create, after all, changes. The human mind vigilantly seeks change. Some do so to follow it, some others to fear it. Even though the discussions around social media tend to care more about how dopamine works, if you zoom out, what they make is a new socio-political layer that enables change.

What’s interesting is the quality of these changes. So far, human society has sought changes that are rational: more, better, stronger. But this new, postmodern mode of creation makes things simply different. In this new culture, the change creators don’t necessarily improve something. They simply share what they mix, improvise and explore.

This is possible because of The Zero Marginal Cost Society. It could have been costly if we didn’t have infrastructures like the web. Since virtually anything can take a digital form and travel to the other side of the globe as a matter of a second, the burden of change is as heavy as air.

Applications of change

Of course, it makes the process of creation highly reliant on the digital technologies. The social media apps are answers to this problem and they are already deeply seated in our daily lives. Not just the media, countless apps have emerged in the last decade to aid the creators so they can navigate the digital environment.

The apps have one thing in common: they are utility-first. Each of them has a vertical where it solves a specific problem. This approach is great when you need smooth user experience for a functionality. YouTube has unparalleled video delivery. Instagram understands what it’s like to upload media from a mobile device.

But the world of software development has grown. There are so many, perhaps an overwhelming number of tools, resources, and providers that facilitate app-building. Small teams, or even an individual can deliver apps that make impact now.

What if an app can be made for a change? rather than a utility. Again, this change doesn’t have to be something righteous. That kind of missions belong to an ideology or a religion. This change is something unique to each of the change-creators.

Entrepreneurial creators already have prepared useful apps under their belts. But the typical software development takes a whole team to manage. Otherwise, the creator has to outsource the app with all the risks on their side, while some others wrestle with no-code tools, if not Wordpress.

Creative collaboration for creator apps

My suggestion is a new model for software development: creative collaboration. Tech start-up founders struggle to find a vertical. Creators struggle to adapt their creative context into the digital world. They can solve each other’s problems. The creator becomes the founder’s vertical, and the founder takes the creator’s vision to the digital world.

The creative vertical is powerful because it’s unique. There’s no real competition. The creator already has an audience to try the app. UX issues can be minimised as it’s highly customised for the specific use cases for the audience.

Quite the contrary, the whole experience of the app can be accepted as a form of communication with the creator. Even the troubles along the way gets a chance to be forgiven because they are from the creator, not some machine glitch.

This new approach has been my personal inspiration. As a kid, I always wanted to create something on the web. While my childhood didn’t work out that way, building on the web still gives me joy.

My motivation with websites was in the expressiveness of them, rather than the technicality. Then I went to art school, received an education in fine art. I was looking forward to work with creative people using the technology.

And I can feel I’m there now. The creative apps idea has become my central theme. I’m not sure how this idea will unfold and transform. There’s only one way to find out.