Programming Design Patterns

Even if you’re an experienced programmer in other languages/environments it is worth doing the Bubble Lessons and Tutorials and at least watching (if not following along with) the “Crash Course” videos. Find all that here: Academy | Bubble

Bubble is essentially a full-stack web development environment (but with a visual programming paradigm) and all of the underlying technologies are the same as in any other web dev environment: HTML, JavaScript, and CSS (and the Bubble database, of course).

Here’s a handful of not exactly “design patterns”, but more basic things that are unique (or unusual) in Bubble that may not be obvious at first:

VARIABLES
While you correctly note that Groups can hold some value, the fact that groups can hold data of some type is typically for allowing some value to “cascade” down the element tree for display in some sort of display element (a text, image, repeating group element, etc.).

More properly and generically, local variables held in memory are realized as “Custom States”. Such states can be put on any element and have no visual representation in the editor or runtime view. You can create them when building an expression with the Expression Builder or by clicking the (i) icon in the property inspector. (You will find much other useful information there as well.)

In this sense they are more akin to adding a property to an object in JavaScipt than to declaring a variable, though creating a new custom state can be thought of as variable declaration.

Option Sets can be thought of as environment variables or system constants (though Things can be used in this way as well).

ARRAYS
Arrays in Bubble are known as “lists”. They are only one-dimensional and have a somewhat strange assortment of operators on them that (oddly and unfortunately) do not represent the entire class of Array methods available in JavaScript.

It’s worth noting that most list operators in Bubble do not operate in an array-like manner, but in a Set-wise manner. That is, they result in deduplication of duplicate values. Lists in Bubble should generally be thought of as Sets. (It is possible to have a list of values that contain duplicates (for example, if you have a List of Things that have a numeric field Number on them, the expression List of Things's Number will be an array of numeric values, some of which may be duplicates. However, operating on that list with any of the set-wise operators (which include the :plus item and :minus item operators) will cause that list to turn into a set.

Here’s an example. We have a list of random integers, now we :plus item 5 to it, attempting to push the value 5 on to the list results in the list being deduplicated and since 5 already exists in the list, it is not appended:

EXPRESSIONS
Expressions in the Expression Builder are complete when the expression’s type has been fulfilled. This makes building certain expressions impossible. Turn on the “experimental” parentheses feature in Settings > Version (down at bottom) and you’ll make Bubble more powerful and your life much easier.

ITERATION
There are no explicit looping constructs in Bubble. No explicit for, for… in, for… of, while, or do… while loop constructs like we have in JavaScript. There is implicit iteration going on all over the place, however. Note that list operators offer some help here, but Bubble is only half-baked as an array-oriented language.

Many things we might do with trivial loops in other environments can be accomplished simply and elegantly with list expressions (e.g., do two lists contain any of the same items? That’s list 1 :intersects with list 2 :count > 0), but the full complement of list expressions we might expect in a truly array-oriented language is missing.

There’s no generic .map() function, but there is one for lists of texts (arrays of strings) in the form of :each item formatted as....

There is a well-specified .filter() operator (:filter) with an “Advanced” option that iterates through the list based on some expression that can reference “this item” (so it’s not like there isn’t a model for how this would work in Bubble’s visual programming paradigm, it’s just that a mapping function is not provided and this is borderline insane and/or cruel).

Edit: :point_up_2: if anyone from @bubble is reading this, it would be trivial to add an “app type” dropdown to the dialog for :filtered and then a second input field (that gives access to the same props as the filter expression dialog) and then let the user write any expression that resolves to the selected app type. For example, if we are filtering a list of Things and want to map to some number, I could write this Thing's value + 1 and, instead of returning the filtered list of things, return the filter/mapped list of numbers instead of the filtered list of Things. And, et viola, you’ve just solved 99% of the front end looping cases and added a map/filter function. Nobody can tell me that this is more than an afternoon’s work. Also, I would stop calling your array-oriented language half-baked, so there’s that.

Backend workflows can be recursive, however. On the client-side (where iteration would be more helpful and faster) you can turn to things like my List Shifter or Floppy plugins for various solutions to iteration/looping/additional array-oriented actions (there are other plugin solutions as well).

OBJECTS
The only type of read/writable object available to the Bubble programmer is a Thing (a custom data type). Things can only be created via interaction with the database (Create a New Thing) and can only be changed by interaction with the database (Make Changes to a Thing, Make Changes to a List of Things). API response objects and options (individual members of an “Option Set”) are also objects, but are immutable/read-only.

Things can be thought of essentially as JavaScript objects and it is best to think of your database as holding JavaScript objects and NOT as “tables”. (The Bubble database does not literally store JavaScript objects in the same way as IndexedDB [which literally does store data as JavaScript objects] but conceptually the Bubble db is exactly like IndexedDB.) The Bubble database is indexed and the primary index is the Thing’s unique ID.

Things are also “custom data types” and can be said to have a data type of that Thing.

DATA TYPES
Bubble as a “programming language” is strongly typed. All expressions have a type. All fields have a type. All values have a type and single values (scalars) are distinct from lists (arrays). Writing an expression that resolves to a type that the field does not expect throws a warning in the Issue Checker.

All of the primitive Bubble data types (yes/no, number, and text) are their JavaScript equivalents (boolean, number, and string).

The Bubble date datatype is a JavaScript date object. The numeric range and date range datatypes are seen in Bubble as scalar values but are two-element JavaScript arrays that represent the endpoints of the range.

For all intents and purposes, the Bubble state known as “empty” or “is empty” is the special JavaScript object null. The Bubble expression “something is not empty” (sometimes found as “isn’t empty”) is the same thing as !something in JS.

In the same way that arrays are never null in JavaScript (because they are objects), lists in Bubble are never empty. As in JavaScript, the correct way to assess whether a list has any items in Bubble is to check its :count (the count will be 0 if the list has no items), which is equivalent to the length property of JS arrays.

Edit: I had meant to comment on undefined… There is no such thing as undefined in Bubble. All properties/things-we-might-refer-to must be declared in some way before we could possibly access them in the expression builder. Mostly this happens automatically (any element in Bubble has a variety of predefined exposed states, for example an input has a value output, which we can access as that_input's value… that value might be empty aka null, but it is never undefined). If something that once existed in a project then goes away (e.g., you delete an entire Thing/custom data type or remove a plugin whose outputs you referred to somewhere), the Issue Checker will throw an issue for any expression that refers to that missing or deleted property showing is as [missing something] or [deleted something].

Negating a boolean: The boolean negation operator is not obvious in Bubble, but it is the expression some_yes_no is "no". This is equivalent to !some_javascript_boolean.

All Things are also data types and an expression that resolves to some Thing or list of Things is said to be of that data type.

That’s all I got at the moment, but perhaps more will chime in here.

18 Likes