A Useless Web Pattern

I love to explore various options for design when doing my deliberate practice. Sometimes I realize that these options are useless in nature, yet try them anyway – because discovering new things is fun! And because you never know what you’ll learn down the line.

While recording a series of videos “Alex learns htmx“, I realized that I could use the state monad to manage state in a web application. At this point, you probably have a bunch of questions: What is a monad? What is the state monad? How would you do that? Why is it useless?

Well, let’s see.

A monad is a design pattern from functional programming. The state monad in particular has the following components:

  • a data structure that contains the current state of the system
  • a function that takes the data structure and evolves it to the next state

The monad itself is a transformation that takes the duo [data structure version n, change function] and returns a duo [data structure version n+1, change function]. (For the knowledgeable reader: I know there’s more about monads than this, don’t @ me)

In my case, I was playing with a to do list that has a list of items: ["Milk", "Sugar", "Bread"]. If I want to add a new item to the list, I can simply have a function addNewItem that receives the current list and returns a list that contains all the initial items plus a new one ["Milk", "Sugar", "Bread", "New Item"]. If I want to rename an item, I can use a function renameItem that receives the item to rename "New Item" and the new value and returns the new value. And so on.

The interesting thing about this pattern, and the reason why it’s used in functional programming, is that it prevents mutation even when we change things. The current state of the system is used as input for a pure function that returns the new state of the system. It is quite a beautiful idea.

How did I use it for a web application? Well, the state is already in the html code, since it needs to be displayed. We just need to pass it to a server-side pure function. In htmx this works beautifully simple through a few html attributes. See below an example of a Jinja2 server-side template that builds the htmx fragment:

<h1 id="list-header-1">First List</h1>
<ol id='list-1'>
{% for item in toDoListItems %}
<li hx-get="/lists/1/{{ loop.index }}/edit" hx-trigger="click" hx-target="#container-list-1" hx-include="input">{{item}}</li>
    <input name="items[]" type="hidden" value="{{item}}"></input>
{% endfor %}
</ol>
<button id="add-item-list-1" hx-post="/lists/1/" hx-trigger="click" hx-target="#container-list-1" hx-include="input">Add Item</button>

Source: https://github.com/MozaicWorks/try-htmx/blob/master/templates/todolist.html

The last line of the code above reads as follows:

  • when clicking the button “Add Item” (hx-trigger="click")
  • make a POST call to /lists/1/ (hx-post="/lists/1")
  • include in the payload all the input fields (hx-include="input")
  • the result of the call replaces the element with id container-list-1 (hx-target="#container-list-1")

In the example, the input fields are hidden and double the li items. On one hand, this is the result of me not figuring out how to send the values of li elements as payload through htmx. On the other hand, the hidden input fields allow for the use of HTML arrays in the payload by using <input name="items[]".

The server side code is pretty basic. It’s implemented in python with Flask and the addItem function looks as follows:

@app.route('/lists/<int:listId>/', methods=['POST'])
def newItem(listId):
    toDoListItems = request.values.to_dict(False)['items[]']
    toDoListItems.append("New Item")
    return render_template('todolist.html', toDoListItems = toDoListItems)

Source: https://github.com/MozaicWorks/try-htmx/blob/master/app.py

Interestingly, this function could also be implemented as an AWS Lambda or another type of cloud function.

To summarize: we send all the data stored on the client to a pure function from the server that returns the new state as part of an html fragment that we display.

So, an interesting pattern, right? We have the state on the client at all times and the server-side code is pure, therefore easier to test and to understand. There’s no database, since all the data is in the page. Sounds intriguing.

So why do I think it’s useless?

I see multiple reasons, but the most important is that the state gets lost once you close the page. This includes browser restarts, navigating away from the page, refreshing etc.

Sure, we can imagine some kind of save, either on the client or on the server – this being the only impure operation we allow. We could save in the browser, which results in the counter-intuitive behavior that data will be different depending on the browser you use. We could save on the server, but that will require a user action, and therefore has potential for data loss. We could also allow a save to a local file (download) and load from a local file (upload). Perhaps some autosave feature can be added.

However, all these options are more complicated than the normal way in which web apps work. Add to this potential performance and security problems, and the pattern doesn’t look that good.

Ah, well, at least it was fun to discover and to use :).

So what do you think? Is this really useless? Have you seen it before? And will you watch the video series when it comes out? (probably at summer time)

More from the Blog

Leave a Comment

Your email address will not be published.

0
    0
    Your Cart
    Your cart is empty
      Apply Coupon
      Unavailable Coupons
      aniscppeurope2022 Get 20.00 off
      Scroll to Top