Many actions, or few mega-actions?

Let’s say you’re making a complex Pack that integrates with an outside service, where you have a dozen sync tables each with a dozen columns.

What’s your design philosophy when it comes to implementing Actions that update data in those columns?

On one hand, you could make an Action per column - UpdateCustomerFirstName(<id>,<newname>)

:+1: Easy for user to use (does what it says on the tin)
:+1: Easy to write autocomplete logic
:-1: Soooo many Action formulas in the Pack - seems overwhelming
:-1: Marginally more annoying for me when developing I think?

On the other hand, you could try to abstract it more - UpdateCustomerField(<id>,<field>,<value>)
:+1: Tidy (one Action formula per sync table)
:-1: User has to correctly supply field name (though you can help them with autocomplete)
:-1: Autocomplete code gets messier with lots of conditionals
:-1: Different columns may require very different API approaches to update, so you do a lot of conditionals in your update logic too

Which do you reach for and why?

First question:

Who do you anticipate your end user being primarily? You as the user or a more general audience (publishing in the gallery) with various levels of Coda skills?

What makes a better user experience for people not as sufficient in Coda?

… has one big advantage that you didn’t mention; supports arbitrary table schemas, right?

Good question. I guess general audience in gallery. If building an internal tool I typically just add individual formulas as the need arises.

But also interested to know if there are best practices that still hold as an internal tool scales.

Hmm yeah good point. I haven’t encountered this very much in my travels yet (just a table that’s mostly predictable, but which the user can add custom fields to; in that case I had an UpdateCustomField() formula)

Ergo, unpredictable. :wink:

It depends on the probability users will expect to be able to customize the solution. I just raised it as a potential advantage for that side of the ledger.

1 Like

General action 100%, don’t even think about an action per specific field, it will be impossible to use for users who want to update more than one at the same time which will be usually the case.

1 Like

Why not a third option! Have every field be an optional parameter:
UpdateCustomer(<id>,<value1?>, <value2?>, <value3?>, ...)

When called users can write UpdateCustomer(5, value3: "hi") for example, even being able to update multiple at once

1 Like

Whoa yeah didn’t think about it this way; I’m so conditioned by Javascript to think of arguments just as positional rather than named. And I still go mostly just positional with my CFL. But I like this…

Is this what you mean @Leandro_Zubrezki when you talk about batching multiple updates to a record with a single call?

1 Like

Yes exactly, entity id whatever it is and then the named parameters with the corresponding type, required or not, etc.

1 Like

Hope you don’t mind feedback from a rando newbie user who hasn’t published a single real pack but hopes to some day.

I like Leandro’s and Rickard’s idea.

This matches how updating multiple fields in CFL works, so it would be familiar to Coda users who already know how to update native table rows.

image

ModifyCustomer(<id>, <field1>, <value1>, <field2?>, <value2?>, ...)

The first three parameters would be required, and any additional parameters would have to arrive in pairs.

It would be a pain to write, but it would be the easiest to use.

If it is overly ambitious for an initial release of the pack, you could start with allowing only one field. Then, in a later release you could add support for multiple fields, and everything would continue to work with no breaking changes.

1 Like

Actually, it’s not a pain at all. The Pack SDK accommodates this interface design pretty well.

Good point about ModifyRows() @Kuovonne

I think the big question then for the mega-action formula is which CFL syntax should we use?

Positional:
ModifyCustomer( 472, "firstName", "Bill", "lastName", "French" )

(implemented with repeating varargParameters of <field>, <value>)

Object-y:
ModifyCustomer( 472, firstName: "Bill", lastName: "French" )

(implemented with a predefined set of optional:true parameters

Positional is needed for Bill’s dynamic schemas. Any other contexts where you’d prefer one over the other?

I was thinking the painful part would be all the data validation and autocomplete. Even though the Pack SDK supports this type of input, putting in the logic for good feedback when users put in bad parameters takes more effort than if you have only a fixed two or three parameters.

In my suggestion where the user lists the fields as parameter, people specify only the fields to modify, in whatever order makes sense to them.

If I understand your object-y method (which I might not), if someone wants to update only the last name, and not the first name, they would still have to have something for the first name.

I believe users can do it like you say - UpdateCustomer(245, “Bill”, “French”)

But I think they can also snipe individual parameters-
UpdateCustomer(245, lastName: “French”)

But I suspect this is not a common way of using CFL formula parameters and could be more confusing to users.

Positional type goes only when you don’t know ahead the key of the property you want to update. For example in the Notion Pack I have no idea about the structure of users databases, so I need to use UpdatePage(472, “firstName”, “Bill”, “lastName”, “French” ) type of action.

When you know exactly the structure of the data you are updating, then you go with Object-y as you can always use named parameters.

1 Like

Oh wow. This is cool. I didn’t realize that one could do this. Thanks for the explanation. I think this is a powerful way to make some formulas easier to read. I didn’t see this feature explained in the formula documentation. I think that it is a little harder to understand, especially as named arguments only seem to apply to optional arguments. Makes me wonder what other hidden gems are in store for me.

If you went with named arguments, you would could only make the customer ID required, since you don’t know which field you want updated. However, there would have to be at least one field updated. So, does the language support having at least one named argument being required? If not, what do you do when there are no named arguments included to provide meaningful feedback to the formula writer? Overall, I think mixing named parameters with positional parameters tends to be confusing.

Yep this is the problem I think haha. It’s a good way to tackle the situation, but one that most CFL users don’t do very often.

While I don’t think you can say “must have one of these optional params”, you can throw a custom error message when the formula evaluates. So you at execution time you could show the user “Oops - you need to provide at least one field to update”.

I think I like this approach. I think it would result in more readable/maintainable Pack code when it comes to things like autocomplete/validation, update logic, etc. And while the CFL syntax might trip up some users, you’re usually providing some examples in a demo doc they can learn from… and once users get how to use it, the resulting CFL is nice I think.

@Eric_Koleda I feel like you’ve probably thought a lot about this - anything to add or are you basically aligned with Leandro above?

1 Like

There’s a third choice and it may seem nutty.

Why not use AI to infer intent?

Make it possible to talk to formulas with natural language.

A little late the party (I was on vacation last week) but yes, I agree with @Leandro_Zubrezki. The key/value pairs approach makes sense when the fields are dynamic, but if they are fixed then I think optional arguments makes more sense.

I also agree in general that it is best to start with a mega-action, but I think it may make sense to add some field-specific actions for the most common use cases. For example, a Todoist Pack may want to have a MarkComplete action in addition to a UpdateTask action, since checking off tasks is likely the most common thing someone wants to do.

Finally, I think the upcoming addition of two-way sync will further reduce the need for field-specific actions. Directly editing the value in the sync table will serve users that aren’t as comfortable with complex formulas, and the mega-action can be used by power-users in their sophisticated workflows.

3 Likes