The 'Golden Rules' of Software Engineering in Bubble

I have an internal list of ‘Golden Rules’ that I use to inform my Bubble development that I’ve picked up from community members or from trial and error.

I thought it’d be fun if we could crowd-source some more Bubble tips + tricks and make a big list!

:question:What’s missing from here? Let me add it on!:question:

  • From @nsykes: Never leave a slug empty. If a data type doesn’t “need” slugs, set one anyway and just Calculate formula Generate random string to a 10 character alphanumerical string. example.com/test/38fn18sd94b looks better than example.com/test/39230423930294830x2014982309432094823
  • From @nsykes: When you can, have the client-side identifier of a piece of data be the slug. For example, the order number of a DT_Order should be the slug. If the client-side identifier has caps in the ID, consider changing it to make it align with slug naming conventions. Discrepancies between spaces/underscores are OK.
  • From @nsykes: If you HAVE to run a ‘Do every X second’ workflow, there better be a conditional set at the workflow level (and not at the first step of the workflow) to make sure we’re only incurring WU when we absolutely need to.
  • From @nsykes: In most cases, the best way to do user permissions in Bubble is to set however many roles you need (employee, manager, admin, etc.) as an option set in Bubble and add a corresponding field in the User datatype. Privacy rules + visibility of elements can be plotted against this.
  • From @nsykes: Naming conventions are very important for keeping track of stuff.
    • Datatypes should have a DT_ prefix (DT_Company, DT_Category, DT_Ledger, etc.)
      • Satellite Datatypes should have an SAT_DT_ prefix.
    • Option sets should have an OS_ prefix (OS_Roles, OS_Color, OS_Condition, etc.)
    • Custom events should have a CE_ prefix (CE_AddItemToPurchase, CE_AdjustReversePagination, etc.)
    • Reusable elements should have a RU_ prefix (RU_header, RU_loadingpopup, etc.)
  • From @nsykes: Conditions are checked from left to right in Bubble. To save on WU, place the conditions that will take the least WU to check first.
  • From @nsykes: When you first login for the day, create a savepoint.
    • When you log out for the day, create a savepoint.
    • When you’re about to do something stupid (and you know it’s stupid), create a savepoint.
  • From @nsykes: If your app has user profile photos, solve against empty pictures by autopopulating empty image inputs with the DiceBear API, which generates custom profile photos. It’s as easy as setting the image URL to ‘https://api.dicebear.com/7.x/initials/svg?seed=Current user's full name’ or your database equivalent. They have many different styles, noted here.
  • From @ranjit and @chris.williamson1996: If you have to consistently run an advanced filter, or use :merge, :filter, :minus, :plus, or have expressions that are over 3-4 layers deep to do a search, there’s a high chance you are using bad optimization practices and can solve it with a database restructure.
  • From @gaby: When filtering a Repeating Group in Bubble, use daisy chain filtering method for the fastest result. Here’s a great video from @Andrew.Vernon: https://twitter.com/Andrew_Vernon/status/1484305152727465985
  • From @nsykes: If you want to toggle DT_Order’s ‘Completed’ using a single button/element, run: change ‘Completed’ to If 'DT_Order's Completed' is no.
    • If ‘Completed’ is no, then it’ll get set to ‘yes’.
    • If ‘Completed is yes, then it’ll get set to ‘no’.
  • From @nsykes: If you have a Datatype with many fields and have to display a Repeating Group with fewer than half of all of it’s fields, use a Satellite Datatype to do so.
  • From @nsykes: If something is not visible, 9 times out of 10 it’s a privacy rule issue.
  • From @TipLister: Need to get specific data about the country a user lives in (image of their flag, their currency, etc.)? A simple API call could be to https://restcountries.com/v3.1/alpha/[Current user's address:extract country]
  • From @nsykes: ‘Dummy run’ crucial plugin actions on page load. You may have noticed the first time you run a plugin after not using it for a while, it takes a minute to execute. If you just run a test action with dummy data on page load, the first time your user engages with the plugin and triggers an action, it’ll run at normal speed.
  • From @adamhholmes: Searching for “DT_Order's first item:is empty?” is faster and less WU intensive than searching for “Do a search for DT_Orders:count is 0”. If you want to earn even more brownie points on WU intensiveness, check out Adam Holmes’ post on a third option.
    • @adamhholmes has clarified that this is only true because of a bug with Bubble; I’ll update this post when the bug is squashed. :blush:
  • From @chris.williamson1996: SPA (single-page applications) should ALWAYS have the main page data type as “navigation” too allow for forward\back browser nav, nice slugs, and all pages should be reusable elements to cut down on clutter on main page & keep editor performance.
  • From @chris.williamson1996: If you get stuck and think your only option is to move to an external db there’s a good chance you’re wrong. Ask the forums for help!
  • From @chris.williamson1996: Never leave a data field “default” option empty for number values (set to 0) or booleans.
  • From @chris.williamson1996: When starting your app make your decision up front on how you handle word casing & trimming.
    • Most of the time [Chris] personally always :lowercase everything in database & use :capitalizedwords for things such as names, company names, etc. This ensures consistency in bubble since searches are case sensitive. Most all items should be saved :trimmed.
  • From @chris.williamson1996: If you use Scheduled workflows on datatypes ALWAYS record scheduled time when scheduling and Completed time when completed (if you use for multiple things opt for a “log” datatype instead). Admin dash should have a display of count items that are past schedule time and completed time = empty.
  • From @chris.williamson1996: GET calls to your API providers are there for a reason. Don’t just use your database as your first line of reference or rely on webhooks. mostly for payments but in all API instances. For major parts of your app run daily, weekly, or monthly checks to ensure your data is in line. Ex) you don’t have items marked in your database as active while stripe as them marked as expired. For these I tend to prefer alerts rather than db changes so I can see the errors rather than just expecting it to fix itself.
  • From @chris.williamson1996: Plugins your apps core features rely on should be built in house after MVP. If this can’t be done you must make contact with the plugin creator in order to see what management looks like & have a backup option on hand.
  • From @chris.williamson1996: Privacy rules aren’t just for security. They also play a big roll in app speed on larger apps. No app should ever hit production without privacy rules setup.
  • From @chris.williamson1996: Most app should never be launched public without google analytics & Facebook pixel tags. We live in an age where data is more valuable than gold.
  • From @chris.williamson1996: Login/Signup pages should be separate. The marketing team will thank you.
  • From @chris.williamson1996: When working with multiple developers documentation is important. If on time/budget constraints.
    • Notion documentation, or equivalent (best)
    • Loom video documentation (better)
    • No documentation (unacceptable)
  • From @chris.williamson1996: Cash flowing production apps should ALWAYS have a backup of the database on an external source.
    • Bubble may claim to have full backups but twice in [Chris’] life [has he] lost unretrievable data by bubble due to bugs even with supports assistance.
  • From @chris.williamson1996: Popups should never be used as “pages”. Keep those for alerts, create, edit, delete actions.
  • From @chris.williamson1996: In your day to day life pay attention to how major companies build & navigate their apps. Pay attention specifically to page utilization, element types being used, & URL structuring with use of params.
  • From @AirDev: When running API workflows in Bubble, the number of items that the workflow has to execute upon has a greater impact on performance than the size of each item. (source)
  • From @djtochner: When creating a looping workflow, make sure you have a safety switch/condition that will shut the workflow down so it doesn’t suck all of your capacity. (source)
  • From @georgecollier: If you find yourself frequently needing to dynamically specify which field to modify on a type, you probably need a new data type where that field is an option set.
    • For example, for order statuses, instead of having fields ‘dateOrdered, dateAccepted, datePacked, dateShipped, dateDelivered’, have a List of Order Statuses where Order Status contains the date and the status (Ordered, Accepted, Packed etc option set). The exception might be dateOrdered which should also be kept on the Order data type for efficiency purposes.
  • From @georgecollier: Anything not protected by privacy rules is public, even if you don’t show it in your app.
  • From @georgecollier: Current user’s logged in is not a sufficient privacy rule if anyone can create an account.
54 Likes

Great stuff, @nsykes. I thought about making a similar thread a few months ago and calling it The First Rule of Bubble after posting this reply. It seemed like it might be fun to have a thread where if folks were forced to give only one rule (meaning it’s the most important rule to them), what would they say?

For me, it would either be privacy rules (anything/everything related to them) or naming conventions. Without those basics, all hope is lost.

4 Likes

Well you earned my heart.

3 Likes

Great post… I might disagree personally with one or two points, but overall a great list :slight_smile:

But just to clarify (in case anyone reading this misunderstands, or hasn’t read my post on this)…

Whilst that IS currently true… it’s only true because of a long-standing bug with Bubble (which they are working on resolving).

In theory, it should 100% be the other way around, and once they (hopefully) fix the bug it should be in practice as well.

(and, as pointed out in my post about this, and elsewhere, you can simply overcome the current bug by avoiding using the number 0, or storing it as a variable first before making the comparison etc.).

5 Likes

I agree with URLs being cleaner and shorter with slugs but be careful!
“Get Data from page URL” will NOT work if trying to fetch a Data Thing using a slug in the URL, it only works with unique IDs. If you change the slug you have to change the datasource to a Do a Search with the constraint Slug=Get paramenter from URL.

I broke my app when setting slugs and I wasn’t happy at all.

3 Likes

Bubble won’t let me create enough savepoints :frowning: Great post!

3 Likes

Love this! All of yours are REALLY good! never heard of dice bear but absolutely will be using from now on. I’ll drop a few of my own below.

  • SPA should ALWAYS have the main page data type as “navigation” too allow for forward\back browser nav, nice slugs, and all pages should be reusable elements to cut down on clutter on main page & keep editor performance. (have a demo if anyone needs it).

  • If you find yourself needing to use :merge, :filter, advanced filter, :minus,:plus consistently in searches OR have expressions that are over 3-4 layers deep to do a search then there’s a 90% chance you are using bad optimization practices and can solve it with a DB restructure.

  • If you get stuck and think your only option is to move to an external db there’s a good chance you’re wrong. Bubble is a very powerful tool and in 6 years there has been 2 problems I’ve not found a solution for that worked well in bubble.

  • Never leave a data field “default” option empty for number values (set to 0) or booleans

  • When starting your app make your decision up front on how you handle word casing & trimming.

  • Most of the time I personally always :lowercase everything in database & use :capitalizedwords for things such as names, company names, etc. This ensures consistency in bubble since searches are case sensitive. Most all items should be saved :trimmed.

  • If you use Scheduled workflows on datatypes ALWAYS record scheduled time when scheduling and Completed time when completed (if you use for multiple things opt for a “log” datatype instead). Admin dash should have a display of count items that are past schedule time and completed time = empty.

  • GET calls to your API providers are there for a reason. Don’t just use your database as your first line of reference or rely on webhooks. mostly for payments but in all API instances. For major parts of your app run daily, weekly, or monthly checks to ensure your data is in line. Ex) you don’t have items marked in your database as active while stripe as them marked as expired. For these I tend to prefer alerts rather than db changes so I can see the errors rather than just expecting it to fix itself.

  • Plugins your apps core features rely on should be built in house after MVP. If this can’t be done you must make contact with the plugin creator in order to see what management looks like & have a backup option on hand.

  • Privacy rules aren’t just for security. They also play a big roll in app speed on larger apps. No app should ever hit production without privacy rules setup.

  • Not all apps are built the same in terms of optimization & quality. When working with clients or your own startup you need to understand your current market position & outlook before starting. Ex) Building a client MVP that’s new to market with a light db outlook on budget constraints does not need to be built out the same with data\workflow optimization, satellite datatypes, custom in-house built plugins, etc as a client that is post revenue needing to scale with less budget restrictions. Ensure you discuss this before making the final decision though.

  • No app should ever be launched public without google analytics & Facebook pixel tags. We live in an age where data is more valuable than gold.

  • Login/Signup pages should be separate. The marketing team will thank you.

  • When working with multiple developers documentation is important. If on time/budget constraints. Notion documentation < multiple Loom video documentation < No documentation (unacceptable).

  • Cash flowing production apps should ALWAYS have a backup of the database on an external source. Bubble may claim to have full backups but twice in my life have I lost unretrievable data by bubble due to bugs even with supports assistance.

  • Popups should never be used as “pages”. Keep those for alerts, create, edit, delete actions.

  • In your day to day life pay attention to how major companies build & navigate their apps. Pay attention specifically to page utilization, element types being used, & URL structuring with use of params.

4 Likes

That damned nft generator

1 Like

DUDE! If bubbles data operation speed wasn’t literally 1000x slower than firebase it could’ve been done!
You knocked that build out of the park though

1 Like

Bubble’s DB is more than enough for 90%
use cases.

4 Likes

Interesting, would you agree with: ‘if a user can create an account, the app should never hit production without privacy rules set up’. I can think of a couple of very basic examples that would require no privacy rules but they basically end at the point that a user can create an account!

If pigs could fly :pig:

1 Like

please upvote on the idea board for Bubble to fix this issue as it should pick up for slugs or unique ids the same way it does when using page current type. Would also be nice to upvote the idea for making it so the URL paths operate the same way as parameters. Also, nice to upvote for idea to get Bubble to automatically URL decode URL paths the same way they do parameters.

1 Like

I’ve gone ahead and edited the list to say this!

What a fantastic list! Thank you so much; there are a few here that are new to me. Everything in my databases are stored as the user input them but I LOVE your reasoning for storing it lowercase. I’ve added yours to the main post. :blush:

1 Like

I’ve updated the post to say that! Thanks for clarifying :blush:

Totally fair. Updated the post to say “if you’re consistently running…” based on discussion below.

Will update the post when the bug is fixed!

I don’t think so! We’re all here to learn and you have a great bank of knowledge to learn from.

2 Likes

Great list! Definitely agree with most if not all of it, and I learned a lot from it. Going to be keeping this bookmarked.

One addition I might suggest, which I’ve come across while working on our apps, is to use an empty “Make changes to…” action as a condition store, when appropriate.

For instance, let’s say you have a workflow in which there are a number of actions that only occur on a specific condition, but for which the condition requires a potentially time-consuming lookup, like only adding/modifying something when an item in the database does not have a certain value.

Instead of adding that condition to every necessary action in the workflow, you can use a “Make changes to…” action to do the lookup once, and then don’t actually change anything with the action. Then every time you need to check for the condition, you just use “Result of Step X”, where the step refers to the empty make changes action, which still contains whatever you found with your lookup.

It’s somewhat situational, but it’s significantly improved the run speeds of a number of the workflows I worked on, since every action didn’t need to do its own search to check for something. Also, I’m still experimenting with this trick, and I think there are other cases where the ability to store an item like a variable in a workflow can be useful.

So I guess in tip form, this would be: Avoid repeating complex conditions in your workflows, if they can be replaced with a parameter passed to a custom event, data stored or displayed in an element, or an empty change action (though the latter will cost WU).

Edit: tip updated based on info from @adamhholmes and @dorilama below. Thank you both! I didn’t realize not changing anything on the database still took up WU.

2 Likes

I had never thought of this before! Does running ‘Make changes to’ without making changes, accrue any WU usage?

Yes it does.

4 Likes

you can actually do the same thing with a custom event: pass the search as a parameter when you trigger the event and reference the parameter in your actions.

3 Likes

It used to be a pretty decent way of defining things (or lists of things) in a workflow, that you could re-use later in the workflow…

But now, thanks to WU costs… it’s not a great way to do things (especially if you’re using make changes to a list of things, to define a list of things) as you incur WU costs for making changes to the thing (or things) even though you’re not actually making any changes (that’s on top of the WU costs incurred for doing the search in the first place)…

Client-side, you can do exactly the same thing with custom states, or custom event parameters, without incurring any additional WU costs (aside from the cost of any search).

On the Server, there’s no obvious native way to do it… but there are plugins that let you define objects and lists of objects…

They’ll incur WU costs, but not as many as making changes to something (or a list of things).

(although you can use custom events just the same on the backend, so that’s probably one way to do it natively)

2 Likes