Function design pattern, how can I create better functions?

Hi,

I have several very simple functions in my controller and they all work fine, but they are almost the same so there is a lot of repeating code and I would like to learn how to design them better. To give you a little bit of context… this is just a testing/learning project where I have products and editing their data is split over 3 different pages.

def edit_basics(conn, %{"slug" => slug}, _current_user) do
    product = Products.get_product!(slug)
    changeset = Product.basics_changeset(campaign)
    render(conn, "edit_basics.html", product: product, changeset: changeset)
end

def edit_images(conn, %{"slug" => slug}, _current_user) do
    product = Products.get_product!(slug)
    changeset = Product.images_changeset(campaign)
    render(conn, "edit_images.html", product: product, changeset: changeset)
end

def edit_pricing(conn, %{"slug" => slug}, _current_user) do
    product = Products.get_product!(slug)
    changeset = Product.pricing_changeset(campaign)
    render(conn, "edit_pricing.html", product: product, changeset: changeset)
end

So, how can I design better functions in these situations where there are several very similar or almost the same functions, preferably with one edit function?

Functions aren’t a limited resource, and stuffing three kinds of functionality into one just makes it harder to read.

You could (in principle) make a function that took the parts that vary here (the changeset function and the template name) as arguments: but then future changes, like adding functionality to just edit_images.html would be harder.

A general controller-design tip: controllers aren’t a limited resource either, so consider making MORE of them to keep things tidy. For instance, the three edit actions above (and their corresponding update actions) could be split apart each into their own controllers with “normal” edit and update actions.

4 Likes

Awesome to see someone else following the same pattern of coding as me.

I follow this pattern in all my code and I named it (several year ago) the Resource Design Pattern, but then a co-worker was always calling it of Resource Action Pattern, and this is in fact a better name for it. I have been lazy and I have not finished yet the repo with the concepts for this pattern, neither I have rename it, but one day will do it.

1 Like

I’d also add that DRYing up those three functions is unlikely a good idea. These three functions do look very much alike today, but the parts being the same/similar are not business logic, but boilerplate. Removing boilerplate doesn’t necessarily improve your code, but most often just makes it more difficult for the three distinct usecases to evolve in isolation to each other, which they likely need to.

5 Likes

As the late great Joe Armstrong would always say:

  1. Make it work

  2. Make it fast

  3. Make it pretty

In this order

1 Like

Except 2 & 3 are reversed…

“Make it work, then make it beautiful, then if you really, really have to, make it fast. 90 percent of the time, if you make it beautiful, it will already be fast. So really, just make it beautiful!”
–Joe Armstrong

14 Likes

Argh. True :slight_smile:

1 Like