Auto Archiving, Sanity Check, Reusable Forms, etc

I wanted to share a few techniques that I just implemented in my app.

A little background…I’m building a process in my app that will replace the email address with a template value. What it does is replace user@email.com with ARCHIVE-user@email.com. The email column is a row owner column. Once ARCHIVE is appended to the email, it becomes an unowned row and is permanently hidden from the app. I’m doing this in an effort to speed up my app by hiding data that’s more than 2 years old. Unowned rows will not be downloaded, and thus, unnecessary computations won’t be performed on those old rows. That should hopefully speed up the app by reducing the amount of data that has to be processed.

I’m doing this for a table that tracks individual student lessons that are taught by a coach. This table gets around 10 new rows per day. This table has become quite large with data going back to the middle of 2019. In that table, I have a math column that subtracts the year that the lesson was taught from the current year and gives me the difference between the years. Then I have an IF column (called CanArchive) that returns true if that lesson is in any year that is older than the most current two years. This means that the row can be archived.

I also have a working table that I use as the driver for my tab to display a list of lessons, as well as using it for a custom form to add new lessons to the lessons table. In that working table, I have a basic boolean column that’s marked as checked/true. I then use that true value to build a single relation to my Lessons table and match up to the first matching row where the CanArchive value is also true. Then I do a lookup of the coach’s email, and follow that with a template column that appends ARCHIVE- to that email. Through a custom action that opens the form, as well as an action that submits (Add Row) the form, I perform a Set Column action that overwrites the email in the Lessons table with the template archive email through the single relation to the Lessons table. This works great and every time the form is opened and submitted, not only will it add a new row to the Lessons table, but it will also change the email in two of the old rows to the archive email, so those old rows now become unowned rows and disappear from the app. Over time, more and more rows will become “archived” and I won’t need to move those rows to a separate sheet. They will just become unowned. This will reduce the number of rows downloaded to the user’s device to just the most recent two years worth.

Now, one thing that worried me is the fact that I use ‘true’ to build my single relation to the Lessons table. What if I happened to uncheck the boolean value accidentally? If that would happen, then all of a sudden, my single relation to the Lessons table would start relating to data in the current two years, and it’s possible that it could start archiving lesson rows that are actually within the current two years. So, I added a sanity check. What I did is create a lookup column that retrieves the CanArchive value from the Lessons table. Then I have an IF column that checks if that CanArchive value is true. If it is, then I return true. Ultimately I have an IF condition in my custom actions that checks if the Sanity Check value is true. If it is, then I will first do a Set Column action to set the email to the archive email, followed by a Show Detail Screen action (if I’m going into the custom form), or an Add Row action (if I’m submitting the form). Otherwise, the custom action will go down another path in the custom action, which will not archive any old rows, but will still perform the Show Detail Screen or Add Row action.

Another trick I figured out is that I can display a single custom form (as a reusable form) called from multiple different actions throughout the app without having to rebuild the custom form each time. There’s been discussion about the advantages and disadvantages of using either the User Profile table for a custom form, or using a separate single row working table for a custom form. I tend to use a separate single row working table more often and I realized an advantage to doing that. I have a tab that is driven from this working table. None of the values from that table are displayed in the tab. Instead I only display an inline list from my Lessons table and a couple of floating buttons. One thing about how glide works is that a detail screen that’s the top level of a tab, or navigated to via a Show New Screen action, will always allow for an independent detail screen layout. However, if you navigate to a detail screen through and inline list, or through a Show Detail Screen action, then that layout is forever attached to the table. Using this knowledge, I realized that my tab can be sourced from the working table, which will have it’s own independent layout, but also, when I use a Show Detail Screen → This Item instead of a Show New Screen → This item, to navigate to my custom form screen, it goes to the detail screen that is attached to the table. By using the Show Detail Screen action instead, I can then call that same Show Detail Screen action, to the working table, from anywhere in my app and end up on the same custom form screen without having to rebuild it. So with a working table to act as a custom form, along with a Show Detail Screen action to navigate to that form, you can then reuse that form anywhere in your app, and you can makes changes to that form once without having reproduce those changes in multiple forms. The only additional thing you need to do this, is add a Single Value column in your other tables that refer to the Whole Row of that working table. Then the Show Detail Screen action will allow you to pick that single value row, which will be your custom form.

It’s been awhile since I’ve made some major changes to my app, so this was a fun little experience. Hope it gives the rest of you some ideas.

11 Likes

Jeff, thanks for sharing your findings in detail (haha ;). I had noticed this post and I’m happy I came back to it. I realize now I need to sit down and experiment because there are points you explain that I don’t yet understand.

On the one hand it’s fun to be able to get better at Glide and delve deeper. On the other, I feel these advanced ways of building, especially if they are both important and bound to be misunderstood by most builders, don’t serve the billion-developers-mission well. Maybe I’m just naive (some parts of any platform will always be complicated) and in any event I need to experiment as I follow along your explanations.

4 Likes

I think I’ve mentioned it before, but I believe that there is a fine line between making the platform more robust while still keeping it simple to use and understand for the average user. Adding more functionality to make some things simpler could potentially complicate the platform as a whole because it just adds another layer of functionality to learn and understand. Glide tries to handle some things for you, but sometimes I want to do things differently to solve my unique problems.

I will agree that Glide could definitely make some things easier, but at the same time, I think there is small number of us that will always push the limits of what glide can do as far as functionality. Plus, you’ll have those that want to fine tune the design of their app beyond what glide provides. I think Glide tries to keep things simple and somewhat locked down to keep things easy, but there will always be those that want more. If glide followed through with every feature request out there, I think the builder could become quite complicated and cluttered with options and features.

To some degree, I think it’s better to understand Glide’s limitations and work within them. Some things just might not be possible and it’s worth exploring different app flows or methods to make an idea a reality. There needs to be an open mind when building an app in glide, because some ideas on paper just might not translate exactly to the final result. If someone wanted full customization and full functionality freedom, then they would be better off learning code and building an app from scratch. Then they could get all of the design and functionality that they wanted. It’s just more complicated due to the open ended nature of a code platform. I don’t think Glide will ever provide every feature that raw code could provide. There’s going to be some limitations to keep the platform usable for a billion developers, but there will always be those determined enough to make advanced logic work within the confines of glide, regardless of how weird of a process it takes to make it work.

I also want to add that a basic understanding of database design is really beneficial, especially for new users.

I definitely understand what you are saying, and I think Glide will improve over time, but a billion developers won’t be trying to do the off the wall things that a small handful of us are doing…but it’s always possible if they are ever willing to logically think through what’s needed to make something work within glide. It just takes a deeper understanding of how glide works, which in some cases is an acquired skill that can’t be easy taught though documentation. You just need to learn through experience, trial, and error.

To further explain the three ideas from my original post and some additional thoughts on each of them:

  • The archiving functionality is primarily for me to reduce the number of rows that load. I have a tab that takes up to 10 seconds to open due to the ever growing number of rows and the sheer number of computations that have to occur on all of those rows… including the old and unused rows. I’ve been fighting various speed related issues with this tab for a very long time, and this is my latest solution to hopefully make the app more responsive and stabilize the number of rows that are downloaded. I think the only solution that glide could provide in this case would be to handle computations server side, and only send data to the device when it’s needed, which could allow for apps to handle larger sets of data. Once glide is redesigned to handle millions of rows of data, then a solution such as changing row owner emails to archive rows would not be necessary.
  • The sanity check is something I ultimately didn’t use because of a technical limitation with the way that I set up my data. The original thought was really to protect myself from myself, so I wouldn’t unintentionally reset a boolean column value from true to false, which is used to create a relation to rows that I want to archive. If the boolean is set wrong, the relation pulls back the wrong rows, and I could inadvertently archive new rows instead of old rows. The sanity check is simply to verify that the related row that I want to update is really a row that should be updated. This is a highly specific use case that most people will never need to account for. Again, the thought was to protect myself from making a stupid mistake, which could mess up existing data. An easy solution from Glide’s end would be if I could avoid creating a boolean column that’s used for the relation and instead I could type in ‘true’ directly in the relation column. Having a separate boolean column that is used in a relation, makes it too easy to inadvertently uncheck the box within the data editor.
  • The reusable form is more of a rediscovery of existing functionality. We know about custom forms, and we know about native forms. Many of us use custom forms for the additional benefits they provide. Honestly, I would prefer to use native forms, but there are some limitations, such as the ability to use real time relations and do real time calculations within the native form. If glide could do those things, as well as provide the ability to use a button to submit the form, then I would be all in on native forms. Also, many have requested the ability to reuse forms in different areas of an app, which for the most part has been thought of as impossible to achieve, and you have to rebuild a form each time you have a new one. One concept that is really hard to explain to people is how and when detail screens become attached to a table. My general rule is that a top level screen, such as a tab or a ‘Show New Screen’ action will always have independent screen configurations. However, anything below that top level, such as navigating to a detail screen through a list or through the ‘Show Detail Screen’ action will have a shared screen configuration that’s permanently attached to the table. It’s a really hard concept to explain to someone and hard to understand until you work with it long enough to understand it yourself. Once you understand it, then it can be really powerful and useful when you need to decide when you need a new or independent details screen layout compared to a layout that’s shared across the app, regardless of how you navigate to that detail screen. Although it’s hard to understand this part of glide, I think it has many benefits and I wouldn’t want it any other way, because it makes things really flexible. But, having this knowledge, I realized that a Show Detail Screen action (rather than a Show New Screen action) will give you a detail screen layout that attached to the table instead of a brand new fresh layout. If that table happens to be a single row work table that is used for a custom form or a tab, then all of a sudden you have a custom form that can be accessed from multiple places in an app, and you will only have to deal with a single design layout for that form, instead of rebuilding it every time you need it, or maintain it multiple times when you need to make changes.

So that was a long rant, but hopefully my thoughts were clarified.

5 Likes

Very very much so. Thank you for taking the time. The ideas you share here are invaluable and are going to help me to understand the inner workings of Glide a little more.

I’ll also look up database design to see if I find a resource that’s simple enough. I do have the feeling that intuitively I’ve developed acceptable practices, but it won’t hurt to formalize things.

2 Likes