Appsheet Work Standard Protocol

APPSHEET
Standard Nomenclature Protocol
 
With great pleasure and enthusiasm, I present this Standard AppSheet Protocol Manual to our invaluable community. I want to express my sincere gratitude to each of you for your continuous participation and contributions, which make our community a vibrant and enriching place. This gift is a small token of my appreciation for all that you have done thus far. I also wish to extend my thanks to Google for providing the platform that brings us together and allows us to grow together. I hope this manual proves to be immensely helpful and inspires even more innovation and collaboration in our future projects! Thank you for being part of this incredible community!
 
INTRO
 
This manual emerges to resolve my own confusions in designing applications with AppSheet. Every time I started a new application, I found myself struggling with urgency and anxiety, moving forward in a chaotic manner and generating unnecessary complexity over time.
 
The main idea of the manual is to address the points left to the developer's discretion, which end up undermining performance.
 
 Here is a compendium of rules that I use in the development of applications with AppSheet, derived from much contributed time, which allows the developer a paradigm shift; abandoning the anarchy disguised as 'freedom' to adopt a protocol that will truly make them free, because if there is one thing I am sure of, it is that one is not more free by anarchically choosing the mode but by being able to develop what we want smoothly within the pre-existing structure.
 
This is not a manual on how to use AppSheet. The objective of this manual is the organization and nomenclature of the elements that make up AppSheet applications. It is not aimed at people seeking to find, here, a step-by-step tutorial on how to create applications. This is not the purpose of the standard.
If you are looking for a book to help standardize nomenclature in the development of applications with AppSheet, this manual is for you.
 
Additionally, I want to let you know that I've added a section at the end of this book about a way to use virtual columns that will help you maximize synchronization speed.
 
APPSHEET
Standard Nomenclature Protocol©
 
PROLOGUE
 
When we were nearing the delivery of an architecture project at university, at the end of each cycle, the computer desks of several of us, at that time students, were filled with files with names as diverse and intuitive as what I write below: 'FinalProject.dwg', 'LastProject.dwg', 'Thisisthelastone.dwg', 'FinalFinal.dwg', 'Delete.dwg'.
 
Some were trash and others important. Backups of these files were simply made by copying them and randomly changing their names.
 
Desk, Table, SmallTable. Objects or blocks suffered the same fate.
In Autocad (the trendy program of that time), we worked with drawing layers. Our work was plagued with layers and files whose origin we did not know; Wall, thick wall, layer 1..2..3...
 
Everything became increasingly difficult to manage as the projects grew. When we delivered, simply that file was of no use anymore. Fix it? It was better to throw it away and start from scratch.
'Some professors used to say, 'We've moved the mechanics of the drawing board to Autocad,' back then, and rightly so. It's because technology has conquered us in the last 20 years, and we've either managed it as best we could or technology has managed us. We've gone from the drawing board to artificial intelligence in less than 30 years.
I finally obtained my degree in architecture, but in parallel, I became interested in application development while trying to optimize my projects with technology.
 
And why do I bring up this story about Autocad? Because it's a personal experience whose analogy is useful to illustrate what I went through with application development on my computer.
In the last 10 years, creating applications has become necessary due to the increasing use of mobile devices and accessible to anyone interested in doing so, especially with the launch of no-code platforms like https://www.appsheet.com (which dates back to 2014 in its beta version and Google's acquisition of AppSheet in 2020).
 
But, just as it is not necessary to have programming knowledge nowadays to create an app in AppSheet, this same democratization of development made many of us work intuitively without questioning how to progress more practically and uniformly, because our backgrounds could be varied, and we knew nothing about the subject. Just log in, and we were already creating applications.
I was one of those who fully immersed myself in it in 2021 without knowing anything about AppSheet, not even that there was a community, which I discovered in 2022. But if I have to admit something, the community has accompanied me a lot. I'll leave the link to my first question in the AppSheet community here https://www.googlecloudcommunity.com/gc/AppSheet-Q-A/Lower-value-greater-than-zero/td-p/290691.
 
Nowadays, I have surpassed 650 posts, including suggestions, ideas, answers, and questions. Google even asked me to make a video recounting my experience since I had participated a lot in the community, but, out of fear, I hadn't done it. Today I regret it because I made this manual after overcoming that fear.
After 3 months of practice, I already had my first application structured. However, full of errors, of course. It was an app to control construction progress since I worked in that field.
So, every time I started a new application, I brought the experiences to the new app to avoid making the same mistakes.
 
One day I decided to stop and see from the outside, study thoroughly what were the causes of the problems in my work and my difficulty in detecting errors, one of them was my anarchy to work and the same disorder I had when I was an architecture student.
 
I asked the community if there was something like an 'AppSheet Standard Protocol,' but I only received responses like 'Everyone works with their own rules,' and that's neither right nor wrong, that's reality. I didn't have any rules either, and precisely that response was the motivation for this manual.
So, I decided to change my way of working in AppSheet to an organized way because having a way is better than having none.
 
Clearly, this manual is the result of my personal work and was made for me because I wanted to organize my work. But clearly, a language spoken by only one person is not a language, so I decided to publish it so that, 'in case the developer is interested in structuring their work, they can adopt some or all of the criteria of this protocol.'
These tips will give your work a very professional structure and save you many hours of work and headaches when you have to maintain them.
 
I hope that in the next pages you receive everything that I could put into practice, in a few pages and without beating around the bush.
 
WHO IS THIS MANUAL FOR?
 
This manual is intended for application developers using AppSheet who seek to improve the quality of their work and increase their productivity. It is a small daily use manual that serves as a standard protocol.
Specifically, this manual is ideal for:
Developers looking for a way to standardize their processes to improve the efficiency and professionalism of their work in AppSheet.
 
Development teams working together to create applications with AppSheet.
Important: I'll say it again. This manual is not aimed at people seeking to find a step-by-step tutorial on how to create applications with AppSheet. This is not the purpose of the protocol. You must have some experience, at least know the interface and how to operate within the editor. If so, this manual is for you.
Here are some examples of how this manual can help you:
  • It will help you create more efficient, user-friendly, and/or maintainable applications (both private and shared).
  • It will help you avoid common mistakes and improve the consistency, quality, and scalability of your work.
  • It will help you work faster and more effectively by freeing you from having to decide things that can be implemented in a standardized way.
 
It will help you collaborate better with other developers.
Have you ever experienced that as the application grows, there is more time between saves? This manual will help you optimize your app's logic to improve management and saving of progress as you work in the editor.
Furthermore, this manual is written in clear and concise language. It is a quick and useful reference that you can consult at any time.
 
HOW TO USE THIS MANUAL?
 
If you have never worked with a standard protocol before, it is advisable to start in the order suggested by the index. If you have been working for some time and want to consult again, you can actually start from anywhere and understand the content.
What is a standard protocol?
"It is a set of rules, conventions, or widely accepted and used specifications for naming elements within a system, ensuring consistency, clarity, and understanding among users and systems interacting with the nomenclature."
It is not the only way to work or the ultimate truth (also adding that it will be constantly evolving), so if you have purchased this book, you will likely see continuous improvements as it will be updated.
This manual is a simple convention that will allow all interested developers to handle the same development language in AppSheet if they wish. And each developer will judge the feasibility of adopting this standard according to their needs.
 
1.0 THE NEED FOR STANDARDIZATION
 
AppSheet has emerged in the technological landscape as an innovative platform that allows users to create custom applications without the need for programming knowledge. This freedom has been celebrated by many but has also brought some challenges, one of which is the lack of standardization in work, not only due to collaboration with other developers but also due to each developer's personal organization.
While the freedom to choose names for component elements is attractive, the absence of a common framework can lead to long-term problems. Imagine a team collaborating on a complex application. If each member uses different naming conventions, communication becomes more difficult, code comprehension is hindered, and project maintenance becomes a titanic task. Everyone speaks their own language.
A standard working protocol in AppSheet not only facilitates collaboration and maintenance but also offers a series of additional benefits, as outlined below, among others:
 
  1. Improves readability: Syntax rules, descriptive names, and a universal language allow immediate understanding of the content of application elements. The use of a protocol becomes a common language adopted by developers.
  2. Reduces errors: Standardization minimizes the possibility of errors when writing names, thereby reducing the risk of application malfunctions.
  3. Facilitates searches: A consistent naming system makes it easier to search for information within an application or among different applications.
  4. Promotes reuse: Standardized names allow for more efficient reuse of code and components.
  5. Increases professionalism: The use of naming standards reflects a professional and organized image of the development team that is not willing to waste time correcting errors that should not exist.
Contrary to what some might think, adopting a standard protocol does not limit user freedom. On the contrary, standardization provides a solid framework that allows users to focus on the creativity and functionality of their applications without worrying about aspects such as naming, iconography, expression handling, and of course, efficiency and optimization.
 
AppSheet is a relatively recent phenomenon, and much of the community navigates on Facebook and YouTube, in addition to the AppSheet community. The democratization of knowledge has made this technology accessible to almost anyone with an idea who wants to turn it into an application and is willing to try.
The community has the opportunity to create and adopt a standard naming protocol that suits the specific needs of each individual. However, here I present my standard working protocol that will be useful for all those who need to adopt some or all of the elements outlined, if they so desire.
This joint effort will allow us to take full advantage of the benefits of AppSheet and turn it into an even more powerful tool for application development.
 
THE INITIAL PURPOSE OF APPSHEET
 
AppSheet was created to make application development accessible to everyone, allowing users to visualize and load content from spreadsheets into an application. This makes it easy for anyone, even without programming experience, to create their own apps.
AppSheet applications are created in the browser from the official AppSheet website and allow for instant visualization of spreadsheet content in user-friendly interfaces or views. These spreadsheets behave like databases. It is worth mentioning that it is also possible to store data in databases created for this purpose.
The database traditionally used by the AppSheet community was Google Sheets and still is today, despite AppSheet releasing its own database and allowing other technologies to be used as databases (such as MySQL, Excel, etc.).
 
In this manual, we will address element naming and key aspects of the Google Sheets database. The goal is to establish a framework that provides developers with greater consistency and scalability in their projects.
We will start by exploring the topic of naming conventions.
 
1.1NOMENCLATURE - APPS AND DATABASES
 
GENERAL RULE
 
The name of the application should be written exactly as the user will see it since AppSheet does not have a 'Display Name' field to write the visible name of the application and another 'Internal Name' field to designate an internal name.
 
For application and database names, lowercase and uppercase letters will be accepted, encouraging the author to use a short name and, if possible, without special characters (!@#$%^&*()+{}[]|:;"'<>,.?/~`), however, this will depend on the branding chosen by the developer.
 
Word separation in the application name will be done with underscores since they are ignored in the UX, appearing as simple spaces.
 
If the application is part of a system of several applications (for example, a restaurant app with areas such as "Purchases," "Warehouse," "Sales," "Engineering"), where each one constitutes an app, two blocks are used to name them:
  • First block → Root name
  • Second block → Section name
If the database is a single one, with all the tables, it adopts the root name of the app. If several independent databases are created, with tables corresponding to each section, they will adopt the app's name including the section name.
 
If hyphens or elements are needed to improve readability, they will be introduced without any problems, for example, following the format shown below: GastroSync_Pro_-_Engineering
This appears on the screen as follows: GastroSync Pro - Engineering
AppSheet does not display underscores in the application.
In the example above, you can see the app name 'GastroSync Pro' and the section name 'Engineering'. 
 
Google Sheets Database
 
When using Google Sheets as our database in AppSheet, folders are automatically generated in our Google Drive directory, within the 'appsheet/data' folder. These folders have a default name that matches the name of the created application, followed by a hyphen and a number that is the unique identifier of the application. We will remove this number so that the folder name matches the application name.
 
Additionally, in the application settings in AppSheet, we must also adjust the name of the folder containing the databases, by entering the name it has in Google Drive. To do this, we must go to 'Settings' in the AppSheet editor and look for 'Default app folder'.
 
It is important to understand the distinction between a spreadsheet and a spreadsheet in Google Sheets. The spreadsheet is the database itself, while the 'sheets', are where the tables of our database are created.
When opting to use Google Sheets, it is recommended that the sheets do not have blank columns or empty rows, and that continuous maintenance is performed by deleting any blank rows during the application's use since deleting a record from AppSheet will leave empty complete rows in the Google Sheets databases.
 
Google Sheets has a limit of 10 million cells per spreadsheet, currently. Please refer to the following link https://cloud.google.com/looker/docs/best-practices/how-to-use-the-google-sheets-integration?hl=es-4....
If we try to create all tables in sheets stored in a single spreadsheet, we may affect performance and information organization.
 
In this protocol, it is recommended to use a separate spreadsheet for each spreadsheet. This way, each sheet will have its own limit of 10 million cells, and each spreadsheet will become an independent database with high capacity. This provides greater flexibility, improves performance, and facilitates data organization.
All spreadsheets for each application or section should be placed in a container folder with the same name as the section or application (as it was created).
 
The name of the Google Sheets spreadsheet will be a combination of the table name and the name of the application to which it belongs, allowing for clear distinction between the spreadsheet and the sheet containing the table. Where the application or section initial goes, the full application or section name will go, thus differentiating the spreadsheet from the sheet containing the table.
 
It will look something like this, let's assume an application called EvoWell:
Container folder name: EvoWell
Spreadsheet name: EvoWell_REGISTER_TUAD
Sheet name: E_REGISTER_TUAD 1.2 NOMENCLATURE - TABLES/SLICES
 
NOMENCLATURE TABLES/SLICES
 
GENERAL RULE
 
"Nomenclature - Tables/Slices
 
The names of tables in AppSheet should follow a specific syntax to improve the clarity and organization of the application's data.
 
Parts of the table name:
 
I_TABLEID_GNL_TUADRO
 
Where:
  • I → Prefix. Initial of the app name
  • _ → Hierarchical separator
  • TRABLEID → Table identifier (name)
  • GNL → Generation/Number/Letter
  • T → Suffix. Table
  • UADRO → Permission suffix
Here's a breakdown of the parts of the table name:
Initial (I): For system-type applications with sections, table names start with the uppercase letter corresponding to the section identifier of the application it belongs to (if applicable). For applications with a single module, the initial will be the first letter of the application name.
Separator (_): After the initial, a underscore is added to separate the initial from the rest of the name, as underscores are used as separators for different hierarchies.
Table Identifier: Following the underscore, the table identifier is written. This identifier should be:
A plural noun in uppercase.
Representative of the main content of the table.
In English, regardless of the language used by the developer; it's a universal convention.
 
Hierarchy level (optional): In case the app's data structure consists of hierarchies on multiple levels, for example, categories, subcategories, types, and instances, it's recommended to use the concept of level or generation.
For indicating the hierarchy level, the following sequence of characters is added to the end of the table identifier:
_Gn
 
Where:
  • Underscore (_): Hierarchical separator.
  • Letter "G" in uppercase: Generation.
  • (n) Integer: Represents the hierarchical level of the element loaded in that table.
  • Permission UADRO: Table permissions are fundamental in defining a table in an application. There are 4 permissions that the user can combine:
  • UADRO → Update/Add/Delete/Read Only
    • Update: Enabled for the user to update data.
    • Add: Enabled for the user to add data.
    • Delete: Enabled for the user to delete data.
    • Read Only: Enabled for the user to only read data.
When choosing the Read Only permission, the other three possibilities (Update/Add/Delete) are deactivated, and when activating any of the other options (Update/Add/Delete), Read Only is deactivated.
However, there's a property of permissions that allows toggling table permissions based on the user:
SWITCH(
USEREMAIL(), 
  "user1@mydomain.com", "UPDATES_ONLY", 
  "user2@mydomain.com", "ALL_CHANGES", 
  "READ_ONLY"
)
 
This suffix in the table naming convention will refer to the table permissions in the editor regarding the user.
At the end of the table, a composite suffix will indicate the type of permission the table has. Following the previous example, suppose we're naming the instances table of food supplies. Its name would be defined as follows:
E_SUPPLIES_G4_TUAD
 
Where:
  • T means Table.
  • UAD means that the user has all permissions on the table (Update/Add/Delete).
Note: It could also have any of the following suffixes, depending on the permissions U, A, D, AD, UA, UD, or RO, in addition to UAD.
 
There's a special case for shared tables, meaning they're used in two or more applications. Since one application may have read-only access while another may allow editing, in these cases we'll use the suffix TS, where T stands for Table and S for Shared. So the table name will be as follows:
E_SUPPLIES_G4_TS
 
This name will help us take special care when manipulating our databases because if we see 'TS' at the end, we'll know it's a table being used by two or more applications.
 
SLICES
 
Slices in AppSheet are custom fractions of tables. They allow filtering, sorting, and displaying only the relevant information for the user. They are useful for improving the user experience by presenting data in a more organized and understandable way. Slices can help optimize application performance by reducing the amount of data requested to be loaded on the screen. They are a powerful tool for customizing and improving the user interface in your AppSheet applications.
 
The naming of slices follows the same structure as tables, with the difference that in the structured suffix at the end of the name, it will have an uppercase 'S' for 'slice' instead of a 'T' for 'table'. Additionally, it carries an underscore to separate the name of the Slice (which will be the same as that of the table) from the purpose of the Slice. This purpose is written without spaces and in UpperCamelCase format alongside the name of the slice. The structure is as follows:
 
I_TABLEID_GNL_SUADRO_SlicePurpose
Following the previous example of the food supplies table, if it were a slice of active supply instances, it would be named as follows:
 
E_SUPPLIES_G4_SUAD_ActiveSupplies
 
From now on, to refer to this naming convention I_TABLEID_GNL_SUADRO_SlicePurpose, in other definitions, I have decided to enclose a shorter representative for the table or slice name in braces, making {table/slice name}, thus avoiding having to rewrite the entire previous nomenclature.
 
1.3 NOMENCLATURE - FIELDS
 
Here we describe the recommended conventions for naming database fields (columns) in AppSheet applications. A clear and consistent naming scheme improves readability, maintenance, and collaboration in application development.
 
General Syntax
Field names are written in singular (unlike table names) with a maximum length of 40 characters and follow the following syntax except for exceptions* that we will see later T
 
T_FieldPurposeIdentifier
 
Where:
  • Initial: T → Prefix, initial of the table identifier. If the table is (for example) O_CUSTOMERS_TUAD, the initial of the table identifier is C because it is the first letter of CUSTOMERS. This initial opens the field name and isolates it in its table.
  • Separator (_): After the initial, an underscore is added to separate it from the rest of the name. We use an underscore since we are composing a name with two elements that belong to different hierarchies; that is, a table (which is a container) and the name of the field itself (which is the content).
  • FieldPurposeIdentifier: Composite name given to the field, which is in camelCase format. It consists of:
    • Identifier: generally a lowercase singular word similar to the table identifier, as it represents the content of the table the most. It is repeated in all fields except for exceptions.
    • Field Purpose: It is the reason for the existence of the field. For Label, the purpose will be Label, for other cases it will be Phone, Email, Address, etc.
For the proposed case, let's assume we are in the table O_CUSTOMERS_TUAD
The fields will look similar to what is shown below:
  • C_customerLabel
  • C_customerAddress
  • C_customerPhone
  • C_customerEmail
Exceptions
 
These are fields whose syntax does not fit the general syntax. Some are mandatory, others optional, and others automatically created. Among them, we distinguish a compilation of 4 types:
  1. Common Fields
  2. Multi-Content Fields
  3. Ref Type Fields
  4. Inherited Fields
 
Common Fields
They are likely to be used in many tables and are repeated systematically.
 
 
 
Field's NameDescription
IDID: Required field, always named "ID" in uppercase. Use UNIQUEID("UUID") as the usual expression. In specific cases, such as tables with constant and read-only content, other values can be used in the ID field, such as in a table of days of the week, where the ID is a sequence from 1 to 7.
indexOptional Field: This field is an incremental numeric counter used to enumerate records in ascending order.
IUDXOptional Field: Unique Duplicated Excluded Index. Virtual filtering column that calculates all records with indices different from the ID of this row. It is not visible but is used to validate the index field of this row, to prevent repetition COUNT([IUDX]) = 0.
UDXOptional Field: Unique Duplicated Excluded. Virtual column that calculates the number of records in the table with IDs different from this row, and then serves to determine the INITIAL VALUE of the index field, COUNT([UDX]) + 1.
LUDXOptional: Label Unique Duplicated Excluded. This is a virtual column that searches all records in the table with an ID different from the ID of this row but with the same name. It is not visible but is used to validate the Label field of this row, ensuring COUNT([LUDX]) = 0.
Row IDAutomatic: This field, called Row ID, is automatically created in the AppSheet database when creating a table, but it is not visible by default. It is not advisable to use it as the table ID, as it can cause problems when migrating the application to another database. Although it copies smoothly when migrating to Google Sheets, returning to the AppSheet database can generate conflicts with duplicate fields. In summary, although it is automatically generated, its use as an ID is not recommended.
Row NumberAutomatic: This field is automatically created in all tables, numbering the rows. We don't do anything with this field.
AnOptional: The 'An' field is a virtual text type field, empty, used to point to 'inline actions'. 'n' represents the action number. There will be as many fields as inline actions are needed.
dateOptional: It's a ChangeTimeStamp type field that stores the date and time when a record was last modified. It's useful for tracking changes in the database.
updateOptional: It's a 'number' type field used to update a table row through actions. It stores a value that increments when a record in the table is updated, recalculating all formulas in the row. This field is particularly useful for preventing misuse of virtual columns
UserIDOptional: It's typically the email of the user logging into the app, and therefore, we use USEREMAIL() in the formula space.
ValidIf|FieldOptional: This is a type of virtual field used to host validation expressions. Its syntax is similar to other non-standard fields, but at the beginning, you write the word ValidIf, separated by a 'pipe'. As expected, it will contain a validation condition, and the data type will be Yes/No (boolean). The name of this column will be placed in the 'Valid if' field of the column to be validated.
ShowIf|FieldOptional: This is a type of virtual field used to host ShowIf field validation expressions. Its syntax is similar to other non-standard fields, but at the beginning, you write the word ShowIf, separated by a 'pipe'. As expected, it will contain a validation condition, and the data type will be Yes/No (boolean). The name of this column will be placed in the 'Show If' field of the column to be displayed.
FRequired: Context Form. Virtual column. It contains a common expression for visual context restriction: CONTEXT("ViewType") = "Form".
NFRequired: Context not equal to Form. Virtual column. It contains a common expression for visual context restriction: NOT([F]).
TRequired: Context Table. Virtual column. It contains a common expression for visual context restriction: CONTEXT("ViewType") = "Table".
NTRequired: Context not equal to Table. Virtual column. It contains a common expression for visual context restriction: NOT([T])
DRequired: Context Detail. Virtual column. It contains a common expression for visual context restriction: CONTEXT("ViewType") = "Detail".
NDRequired: Context Detail. Virtual column. It contains a common expression for visual context restriction: NOT([D])
HDRequired: Host Device. Virtual column. It contains a common expression for visual context restriction: CONTEXT("Host") = "Device".
HBRequired: Host Browser. Virtual column. It contains a common expression for visual context restriction: CONTEXT("Host") = "Browser".
 
 
Content Field
We had said that all fields are written in singular; however, fields of type 'Enumlist,' which store many fields simultaneously, are named in plural but still follow the same general format. Example:
S_suppliesAllowedBrands
Indicates a list of allowed brands for a supply. 
 
Ref type Fields
Fields of type 'Ref' in AppSheet are used to store information from another table using its row ID. Following the convention of the AppSheet editor suggests naming these fields the same way as the table they reference, as when choosing a field from another table to create a dereference in the expression editor of a 'Ref' type field, that dereference expression [tableName].[dereferenceField] will be automatically generated. Therefore, when using a 'Ref' type field, it is advisable to name it the same as the referenced table, which will save time in editing. For example, if we are referencing the table 'O_CUSTOMERS_TUAD,' the 'Ref' type field should be named the same.
All 'Ref' type fields will have the name of the table they come from. However, there are cases where it is necessary to store two or more references to the same table in the same row. AppSheet's default behavior in these cases is simply to incrementally enumerate the field as identical fields are copied. For example, imagine a column called E_PROCESSES_GIII; when another 'Ref' type column from the same table E_PROCESSES_GIII is created, AppSheet incorporates a number (1) in parentheses at the end, separated by a space, to avoid duplication, thus becoming:
E_PROCESSES_GIII (1)
The first column will retain the original name, and the subsequent ones will acquire an automatic appended numbering. We will adopt AppSheet's natural way of behavior without modifying it.
 
Inherited Fields
We call fields that are copied from one table to another, or those that are present in two tables and contain exactly the same information in both tables, 'inherited fields.' These fields will retain the same name as they have in the source table regardless of whether they are in another table. This is practical when creating actions or bots.
 
1.4 NOMENCLATURE - VIEWS
 
In AppSheet, views serve as the user interface. Currently, there are 11 types (as of 2024), but this doesn't mean more won't be created in the future. In fact, a highly requested view type is the Gantt chart, which AppSheet doesn't yet have. These are:
  1. Calendar
  2. Deck
  3. Table
  4. Gallery
  5. Detail
  6. Map
  7. Chart
  8. Dashboard
  9. Form
  10. Onboarding
  11. Card
 
The decision of how to display app information to the user depends on the developer.
All views are created based on a table in the database or a slice. It is proposed to name them the same as the table, in uppercase. Next to the table name, place a vertical bar or pipe ‘|’. To the right of the pipe symbol goes the name of the view itself. Structure of the view name:
{table/slice name}|V_1_2_3
Where:
  • V → Letter V, indicating View.
  • 1 → View name (describes its purpose).
  • 2 → View type (as listed earlier). If AppSheet adds more types, the naming structure remains the same.
  • 3 → Display device: This data gives us an overview of the device on which the view will be displayed. B (Browser) or D (Device). 
There are shared cases, such as when the same view is displayed both on a browser and on a device, in those cases we will use X as a representative letter for the intersection between both types. 
For example, the view where the user reads "Clients" as a table type for the browser (but also on mobile) will be called:
 
O_CUSTOMERS_TUAD|V_Customers_Deck_X
 
Note: It might seem redundant to name Customers again when it's already explicit in the table name, but it could happen that, from the customers, we want to show a map of addresses, for example. In such cases, this structure provides a lot of freedom and clarity since all elements are perfectly delimited.
Similarly, it might seem redundant to write a V before the view's content, but I emphasize that writing it allows us to quickly visualize that it is a view in the editor, useful after several hours of work.
Note: Since it's possible to create views from slices, in those cases, the place of the table name will take the slice's name.
 
O_CUSTOMERS_SRO_Active|V_Address_Map_D
 
It's easy to understand that this is a mobile map view of the Slice Read Only of active customers where we visualize the addresses.
 
Thus, we can name all the views of the application and visually maintain a clear interface in our app editor, which will promote faster and more professional development, as searches become much simpler.
Visible view name (display name):
 
The visible name for the user will be inserted between quotation marks within the Display Name field and is completely free, depending on the developer's needs (as long as it treats the content as a title).
There are cases where quotation marks can be omitted, but others where they cannot, especially when using special characters. However, when some views use quotes and others do not, uniformity is lost at the expense of not gaining efficiency, so the rule is to use quotes in all display name cases.
Icons:
 
For views typically seen on a home screen, icons should represent the purpose of the view. There are no limits in this case as it relates to User Experience.
 
For views not visible in the interface, i.e., 'ref' type views, the only suggestion is to standardize the icons, meaning all table-type views have the same icon, all deck-type views have the same icon, and so on with the 11 types, preferably choosing those AppSheet defaults to for the respective view.
 
Additionally, AppSheet creates views automatically. It's decided not to use them as final views but to create copies of them for use and rename them according to the protocol. In these cases, it's also recommended to use the same default icons suggested by AppSheet.
 
1.5 NOMENCLATURE - BEHAVIOR ACTIONS
 
Behavior actions in AppSheet are a powerful feature that allows customization and enhancement of application interactivity. These actions define how applications behave in response to user actions, such as clicking a button, swiping left or right, or completing a form.
They are actions that are executed automatically or manually in response to specific user events in an AppSheet application.
Some of them are automatically created when creating views and granting table permissions, which saves production time. However, AppSheet offers a wide range of possibilities for creating actions.
Automatically created actions are also automatically named. Some of them are:
  • add
  • delete
  • edit
  • Compose Email (User ID)
  • View Ref (TABLE)
These names are repeated in all tables and will not be altered. Additionally, having these elements previously created with those names allows us to differentiate what AppSheet has created from what we have created in the app.
There are currently (2024) the following list of possible behaviors; 4 major sets of behaviors; App, Data; External, and Grouped.
For the Behavior case, we will associate behaviors with numbers. So:
App = 1, Data = 2, External = 3, and Grouped = 4.
 
In each set, there are actions: 7 App actions, 4 Data actions, 5 External actions, and 1 Grouped action, as shown below (the number in parentheses will be chosen for the convention):
  • App: copy this row and edit the (1-1)
  • App: edit this row (1-2)
  • App: export this view to a CSV file (not a row-level action) (1-3)
  • App: go to another AppSheet app (1-4)
  • App: go to another view within this app (1-5)
  • App: import a CSV file for this view (not a row-level action) (1-6)
  • App: open a form to add a new row to this table (not a row-level action) (1-7)
  • Data: add a new row to another table using values from this row (2-1)
  • Data: delete this row (2-2)
  • Data: execute an action on a set of rows (2-3)
  • Data: set the values of some columns in this row (2-4)
  • External: go to a website (3-1)
  • External: open a file (3-2)
  • External: start a phone (3-3)
  • External: start a text message (3-4)
  • External: start an email (3-5)
  • Grouped: execute a sequence of actions (4-1)
  • The naming convention for actions will be as follows:
{nombretabla/slice}|A_n-n_actionPurpose
  • '|' → Hierarchical separator "pipe"
  • A → Indicates that it is an action
  • n-n → Indicates the action number we saw above
  • actionPurpose → purpose of the action, which should be in camelCase format in English. The name should be short and perfectly express the purpose of the action.
A generic case following the nomenclature would be:
 
I_TABLEID_GNL_TUADRO|A_1-5_goToDetailView
 
Note: again here, it may seem redundant to write A to denote that it is an action, however, it is possible that after hours in front of a monitor seeing names, we may momentarily confuse views with actions. To differentiate them, that "A" before the purpose of the action visually helps a lot, while also giving us information about what is there since both sections are relatively similar visually speaking.
 
1.6 NOMENCLATURE - BOTS
 
"Bots are exactly that, 'robots,' because they do work for us. That's the name AppSheet gave to the feature that allows tasks to be executed when events occur in the application.
So, an event in an AppSheet application is something that happens when three situations occur. Here's the nomenclature:
 
Data Change → DC
Time Change → SC
Chat app → CA
 
These events are taken into account by the bots to perform tasks, actions, and other things automatically. Each time an event occurs, an algorithm is executed. These algorithms are reusable, so there's no need to create them multiple times.
The nomenclature for events will be:
  • {table/slice name}|E_DC
  • {table/slice name}|E_SC
  • {table/slice name}|E_CA
 
There are also Steps or steps of the algorithm that the bot will execute sequentially. The following types are:
  • Run a task → RT
  • Run a data action → DA
  • Branch on a condition → BC
  • Wait → WT
  • Call a process → CP
  • Return Values → RV
 
The nomenclature for processes will then be:
  • {table/slice name}|P_RT_Purpose
  • {table/slice name}|P_DA_Purpose
  • {table/slice name}|P_BC_Purpose
  • {table/slice name}|P_WT_Purpose
  • {table/slice name}|P_CP_Purpose
  • {table/slice name}|P_RV_Purpose
  • The structure of the bot name will be:
  • {table/slice name}|BOT_Purpose
  • {table/slice name}|BOT_SC_Purpose
  • {table/slice name}|BOT_Purpose
 
Bots - Icons:
 
It's suggested to keep the bot icon since the purpose will define what the bot will do, and the icon will help remember the section we are in within the editor. 2.0 BONUS - GOOD PRACTICES
 
BONUS - GOOD PRACTICES
When working with AppSheet, it's crucial to understand and apply best practices to ensure optimal performance and efficiency of your applications. Some important tips include using virtual columns appropriately to optimize app logic, structuring your data and processes clearly and modularly, and minimizing complex expressions that may slow down performance. Additionally, it's crucial to follow an organized methodology when designing forms and views, ensuring they are intuitive and easy to navigate for end users. By implementing these best practices, you can create more robust and maintainable applications in AppSheet. 2.1 VIRTUAL COLUMNS
 
VIRTUAL COLUMNS
 
In the first edition, this was not a section of a chapter, but rather a suggestion within a chapter. However, since I've seen the need to clarify many controversial points about virtual columns, I have decided to do so.
A 'world' of virtual columns has been created, and I myself have worked in AppSheet feeling afraid to use virtual columns because they would supposedly 'reduce performance.' This is a half-truth.
When we create virtual columns, we are creating fields that do not exist in our databases but directly in the logic of the application. When we open an expression container field and insert an expression inside (whatever it may be), we are asking AppSheet to perform a calculation with the expression in that field, in other words, we are consuming resources since each time data related to that virtual column is accessed, the platform must evaluate the expression in real-time. This can affect the performance of the application, especially if the expressions are complex or if there are a large number of records or if the computer resources are not very good (common case).
Fields in AppSheet contain predefined properties, meaning they are also like fields that are calculated in real-time in the app logic and are not in our database, which have the same effect as a virtual column because they consume resources. These fields include, among others:
  • Formula
  • Show?
  • Valid?
  • Editable?
  • Required?
  • Initial Value
  • Display Name
  • Etc., etc., etc...
All fields that require an expression are calculated and of course, consume resources, the same resources consumed by a virtual column.
So, does a real column also consume resources? Yes, absolutely!
Have you ever experienced AppSheet taking a short time to save changes at the beginning and then extending as the app grows? I have, in fact, for a long time, I used to write validation expressions directly in those fields. Saving took longer each time, and I didn't understand why, and this is because I came from an environment unrelated to programming, so I allow myself to fail in this, because I am not yet a programmer. However, as a result of my studies, some concepts have been possible to apply here.
 
Some expressions consume a lot of resources, others not so much, however, writing them directly there can, in addition to slowing down work in the editor, make application maintenance difficult.
Let's consider a common scenario: when editing a form, we need the fields to be presented in a structured way, that is, the next field should be displayed once the previous required field is completed. To achieve this, we usually use a validation expression in the 'Show If' property of each field, which determines whether to show the field based on a condition. For example, we could use the expression ISNOTBLANK(PreviousField) to show the field if the previous field is not blank.
 
As we progress through the fields, we can follow the same structured logic by either copying the formula from the previous expression or creating a 'path,' adding conditions to it.
However, copying and pasting the expression into each field and enlarging it solves the problem but is not optimal since we are asking the platform to recalculate the same thing it has already calculated in another column, over and over again, which is unnecessary.
 
Instead, it is preferable to calculate each new condition in a virtual column and then reference that column in the 'Show If' property of the corresponding fields. This is similar to creating small encapsulated objects that can be used and reused in different parts of the application, avoiding duplicate calculations.
For this, let's consider the following example. Let's establish validation to show the next field in a virtual column named [ShowIf|customerPhone], and then create the validation for the subsequent field in another virtual column called [ShowIf|customerEmail]. In the validation expression of the virtual column [ShowIf|customerEmail], instead of duplicating the validation formula of the previous field, we simply reference the name of the previously calculated column. This way, AppSheet can read the result instead of having to recalculate the expression.
 
For the next example, I will use similar names to better convey the idea. Let's assume we have 4 fields to display:
  • O_customerLabel
  • O_customerPhone
  • O_customerEmail
  • O_customerAddress
A bad practice would be to write validations directly within the 'show?' property of each field, for example:
O_customerLabel: (always visible) 
show? property with active checkmark
 
O_customerPhone (visible if O_customerLabel is not empty):
ISNOTBLANK([O_customerLabel])
Email (if both previous fields are not empty):
AND(
         ISNOTBLANK([O_customerLabel]),
         ISNOTBLANK([O_customerPhone]) 
        )
O_customerAddress (if all previous fields are not empty): 
AND(
        ISNOTBLANK([O_customerLabel]),
        ISNOTBLANK([O_customerPhone]),
        ISNOTBLANK([O_customerAddress]),
       )
 
Imagine for a moment longer forms, with more rows, the time it would take to maintain the application. If any element is modified, all expressions in the 'show?' properties would need to be modified, and the time it would take AppSheet to synchronize everything and save changes if it has to perform these calculations that it already did, over and over again, would be ridiculous and impractical.
 
This is where I encourage creating virtual columns because they serve a purpose that has given me great results, not only for the neatness I achieve in my applications and for forcing me to understand the logic and algorithmic paths of my work but also because maintenance is only done in one virtual column since there are no expressions in the other places, just names pointing to the virtual columns containing the expressions that are performed and calculated only once, and that AppSheet reads without affecting performance. The correct way, in my opinion, would be to create the following logic.
 
Field [O_customerLabel] with active checkmark
 
Virtual Column [ShowIf|O_customerPhone]:
 
ISNOTBLANK([O_customerLabel])
 
Virtual Column [ShowIf|O_customerEmail]:
 
AND(
         [ShowIf|O_customerPhone],
         ISNOTBLANK(O_customerPhone)
         )
 
Virtual Column [ShowIf|O_customerAddress]:
 
AND(
        [ShowIf|O_customerEmail],
        ISNOTBLANK(O_customerEmail)
        )
 
In each case mentioned, what we are doing is optimizing the logic of our application by encapsulating expressions in virtual columns that we can reuse in different parts of the application.
So, the field [O_customerPhone] will have within its 'show?' property simply the name of the column [ShowIf|O_customerPhone] since its result is of the requested type Yes/No.
The field [O_customerEmail] will have within the 'show?' property [ShowIf|O_customerEmail].
The field [O_customerAddress] will have within the 'show?' property [ShowIf|O_customerAddress].
Visually, it is more efficient, it is easy to know what we are referring to, and furthermore, it does not impact the performance of the application as it would if we had to repeat each expression one by one.
For the rest of the properties, we will use the syntax:
 
  • [ValidIf|Field],
  • [Required_If],
  • etc.
 
Thus, for every virtual column created whose purpose is related to a field property of an existing real column and which will be repeated at least once.
When the need arises to create a virtual column to display something in the application, the nomenclature of the columns will be treated the same as that of the real columns except for the exceptions already mentioned. However, be careful here, it is important for the developer to analyze whether creating the virtual column will optimize the logic. For cases where optimization is not verified, directly adding the expression in the predefined field.
As for their ordering, it will be done according to their use, first those that need to be calculated earlier and then those that need to be calculated later. Keep in mind that in AppSheet it is not possible today to order virtual columns, but that may be possible in the future. In any case, I consider it extremely important to have the application structured beforehand, with its algorithm resolved, and flow diagrams created. Trust me on this point because it will save you a lot of headaches. I leave you a link to a website where you can create flow diagrams:
 
 
Even so, the creation of virtual columns must be done with great care because it is true that it consumes resources, but it is worse to reiterate calculations that have already been done in the logic of the application.
With this technique, I have achieved applications that went from having 40 real columns and 10 virtual ones to having applications with 40 real columns and more than 50 organized virtual columns. However, in the first case, all expressions were in their respective fields and in the second case, encapsulating the expressions in virtual columns and reusing the results in the respective fields. As a result, for the first case, 15 seconds of waiting between saves, for the second case, 3 seconds of waiting between saves. I have reduced synchronization and save time by 5 times, and I have improved the logic, as well as the maintenance capacity and scalability of the applications.
 
FILTERS, SELECTS, AND OTHERS
 
The virtual columns created by AppSheet for related records are automatic; if you try to delete them, they will be created again when you save the changes. However, they are very useful since inside they have the following expression:
 
REF_ROWS("Child Table", "Current Table")
 
This means that a list is created with all the IDs of the child table that contain in their row the ID of this current table. In simpler words, they are all the records related to the currently selected record; for example, if in the table there is a country field, where countries are stored, and there is another table called provinces, it will surely have many provinces from different countries. This will make it possible to add a province and assign it a country, and in the country table, there will be an automatically created virtual field that can contain all the records of provinces related to that currently selected country. This field is extremely useful as it allows us to work with this already created list of related IDs without having to create another filtering expression that will impact the performance of the application again.
 
It is possible to use that virtual column for calculations simply by using a dereference expression. For example, to know the population of a country, just by doing:
 
SUM([Related 'Provinces'][Population])
We will obtain the sum of the population of the provinces of a country. This saves us from having to do SELECT(
Provinces[Population],
[Country] = [_THISROW].[ID]
)
 
We will minimize the use of complex formulas, limiting as much as possible the use of SELECT(), FILTER(), and other filtering formulas. We will use dereferences instead of creating another SELECT(). Remember that dereferences in AppSheet can be created by collecting data from several successive tables.
Another example. Suppose we are in a child table of another table and we need only the child records of the parent record to be displayed. A common (but inefficient) case is to create a filter like the following:
 
FILTER(
              "ChildTable",
              [ParentID] = [_THISROW].[ParentTable]
               )
 
It is inefficient because we are asking AppSheet to do again something it has already done in a virtual column; the Related ChildRegister.
Clearly, a better solution is to simply read what AppSheet has already done, for example, by placing in the 'Suggested Values' property a dereference expression like the following:
 
[ParentTable].[Related ChildRegister]
 
As simple as that. The idea is not to calculate things twice but to reuse. Whether the column is real or virtual, it doesn't matter if calculations are unnecessarily done, resources will be consumed excessively.
I hope this tactic serves you well and brings you good benefits, and still, always use judgment when applying it.
 
2.2 DATABASE
 
Comparison between the most popular databases used by the community in applications with AppSheet.
 
Here are some of the characteristics of both technologies. It's advisable to analyze which is the best option before starting, as both are excellent choices.
In the case of AppSheet DataBase, there's not much to do as it's the ideal environment for storing data, although some opt for other possibilities.
 
In this manual, we'll focus on Google Sheets as the quintessential free version of databases for the non-programming community (which is the one that's growing).
 
Table headers in Google Sheets
Table headers in Google Sheets will have a color scheme that doesn't respond to the data type in Google Sheets but to the data type in AppSheet for quick understanding of data types and fields it contains. Below is the convention:
 
ID → Black background with white bold letters. It's the only field with a black background for easy recognition.
Common real fields (exceptions): UserID, Date, etc. → Dark gray background (#999999), black letters, bold.
Uncommon real fields (fields specifically created for each table) → Will have colors according to the data type as explained below.
Data Types (10/34)
AppSheet currently has 34 data types that can be grouped into 10 categories (in fact, the AppSheet documentation does so):
 
 
Change control data: White background, black letters.
  • ChangeCounter
  • ChangeLocation
  • ChangeTimestamp
 
Communication: Light berry red background (#e6b8af), black letters.
  • Email
  • Phone
 
Content: Light red background (#f4cccc), black letters.
  • Image
  • Drawing
  • File
  • Video
  • Thumbnail
 
Enumeration: Light orange background (#fce5cd), black letters.
  • Color
  • Enum
  • EnumList
  • Progress
  • Ref
  • Yes/No
 
Mappable: Light yellow background (#fff2cc), black letters.
  • Address
  • LatLong
  • XY
 
Numeric data: Light green background (#d9ead3), black letters.
  • Decimal
  • Number
  • Percent
  • Price
 
Display: Light cyan background (#d0e0e3), black letters.
  • Show
 
Temporal: Light cyan blue background (#c9daf8), black letters.
  • Date
  • DateTime
  • Time
  • Duration
 
Text data: Light blue background (#cfe2f3), black letters.
  • Text
  • Name
  • LongText
 
Other data types: Light purple background (#d9d2e9), black letters.
  • MultiColumKey
  • Url
  • App
 
Note: The colors mentioned here can be perfectly found in the Google Sheets interface.
While it's not possible in Google Sheets to format columns with all the data types of AppSheet (which can be done in the ADB), the column format in Google Sheets should not override AppSheet when writing in them. For example, fields of type "date" should be configured as date and also, if they include time, they should allow hosting hours since later from AppSheet, this data will be read and/or modified.
On the other hand, the regional configuration and time zone of the spreadsheet must be the same in AppSheet to avoid data conversion problems.
All tables will have conditional formatting that colors empty cells as "light gray 2", making it visually easier to overlook them during manual data tracking.
 
EXPRESIONS - WRITING
 
Typically, when we talk about 'rows' in a text editor, we refer to a complete line, and with 'columns,' we refer to the vertical stripes containing characters.
Therefore, there is what is known as a 'monospace font,' which allows all characters to occupy the same horizontal space for clean visualization in the code editor. This is different from the proportional fonts we usually see, where letters like 'i' take up less space than 'm'.
The fixed width of characters is essential for the code to be displayed correctly aligned and easier to read and interpret by the developer. It allows programmers to see the structure and indentation of the code clearly.
Understanding this, it will be easy to adopt an attitude towards indentation.
Expressions will be written in uppercase and with indentation so that each internal term has a line break after each comma or beginning of a parenthesis if the contained expression is too long.
In addition, expression parentheses (opening and closing) should be aligned. This is known as 'clear format' or 'readable format.' This approach aims to improve the readability and understanding of the source code (in our case, expressions that are a type of code) by presenting the expression structure in an orderly and visually coherent manner.
By adopting this writing style, each component of the expression is placed on a separate line, facilitating the individual identification and understanding of each term. Aligning parentheses provides a clear visual guide to the hierarchical structure of the expression, helping to distinguish code blocks and understand the relationship between them.
This format not only improves readability for the person writing the code but also facilitates collaboration and code maintenance over time. When the code is organized clearly, it's easier for other developers to understand the logic behind the expression and make modifications or corrections when necessary. In summary, clear formatting is a recommended practice for maintaining more understandable and easily maintainable code.
Operators
 
In AppSheet, the following comparison operators exist:
  • = → equal to
  • <> → not equal to
  • < → less than
  • <= → less than or equal to
  • > → greater than
  • = → greater than or equal to
 
Operators should always be written with a space between each term; for example:
  • a = b correct
  • a=b incorrect
This improves code readability.
 
Convention dictates that lesser or greater than operators are written first, followed by the equal sign.
  • a <= b correct
  • a =< b incorrect
Data Access Management
Whenever possible, use security filters that can reduce the amount of data loaded for each user every time they enter the app, reducing synchronization time and data consumption.
 
Testing and Continuous Optimization
Utilize AppSheet's performance monitoring tools to identify bottlenecks and areas for improvement in your application.
Conduct thorough testing on different devices and network conditions to ensure consistent performance in all situations.
 
FAREWELL
Optimizing efficiency and performance in AppSheet applications, being neat in your work, and doing it professionally is essential to offer a satisfactory user experience and ensure developer productivity. By following best practices in data design, formula optimization, synchronization management, and user interface design, it's possible to create fast, responsive, and reliable applications that drive business success.
Remember that optimization is an ongoing process, and it's crucial to conduct periodic tests and adjustments to maintain application performance at its optimum level.
I recommend studying the problem to be solved before starting to create in AppSheet. An algorithm precedes the writing of code, of course, it also does regarding the creation of applications.
I hope I have provided you with useful tools in a concise, straightforward manner so that you can have the best practices in application development. 

I wanted to apologize if my translation isn't entirely accurate; however, I'm open to corrections to improve the understanding of this manual.
 
Sincerely, Gustavo
7 13 579
13 REPLIES 13

Of course please go ahead and do i!

Good Rifad!! Thanks for your reply. I'm going to do this. Can you tell me in which sector of the community these posts are so I can write them?

Hi @Rifad I have edited this message, here is my protocol

Awesome! Everything looks great! Do you by any chance have a sample app that we can check out?

Actually the ones I have are private, but don't worry, you have one and I will leave it here so you can replicate it. I will try to do it tonight, it will be ready tomorrow at the latest. The idea is that you see the concept. Thank you for requesting it. 

It is important that we, the users of the community, see a way to agree to develop with the least amount of time invested in the platform. A standard does that, it is simply like having decided in advance what clothes I will wear tomorrow when I get up, there is no need to think, it is already decided. It also allows you to maintain a certain order that visually (at first) may seem strange but with an hour of work everything becomes simple.

 I've been promoting for years certain naming conventions, and a bunch of other stuff, but it's largely gone on deaf ears. A few people have picked it up, and they've discovered the benefits of standardizing things like this. 

At one point I put something together about this... I think it was a post here in the community, or maybe a YouTube video. I make so many things, and I've been doing it for so long, it's hard to keep track of any of this stuff anymore. 🤪

Nice work! There's some good stuff here, hopefully it helps others with their projects! 💪


@Gustavo_Eduardo wrote:

Use FILTER() when it is necessary to obtain Row ID because it is the most direct expression for it, above SELECT().


Except this is not advisable.... The select statement (and it's port FILTER) should be the last thing you do - an absolute last ditch effort with nothing else worked.  (It's too computationally heavy.  I commonly refer to it as brute force!)

OK. If you want, @MultiTech will add you as a collaborator and let's leave the post open so that it can begin to be enriched and refined. Maybe there are other people who add. Thanks for your contribution!!!! It's time for us to take a step in our way of doing things. It is our language and we must choose how to speak it.

I have corrected what you suggested, you are right. This is what I wrote, tell me if you think:

"Using FILTER(), SELECT(), or any list selection is resource-intensive. It would be best to explore other options before resorting to them. There are dereferences or columns like the Related fields created by AppSheet that you can reference directly without needing additional filtering."

Nice update!

@SkrOYC 

@Rifad I have put a link that will take you to an example app created with the protocol. It is not too different from the rest but you will see that there is some uniformity in the columns. I don't know if it's the best example, it took me an hour.

Thanks @MultiTech for tagging me, this looks promising.

Although I have other methods and may not agree to follow some of the things expressed here, you have done a wonderfull work @Gustavo_Eduardo, I'm very proud.

Somewhere I read that the best convention is to have a convention, meaning that even if the method is not the best, the fact that you apply it is better than no method at all. Or, in other words, is hard to debate whether a method is better than other, but together represent an effort that uppers the game from no having one.

Just in case you are curious, my method for column and table names is similar to yours, but I tend to not promote it too much because most people have a strong opinion against it and it's to have a suffix at the end of the table name and the same suffix as a prefix in each column of such table. That makes all field unique in the context of the database. I then use a prefix of the table's suffix instead of the table name when creating views, actions, etc...

I liked that you also mentioned some convention for actions. I tend to be focused on the behaviour side of things instead of the "visual" (UI) one so I don't think about this too much. I always use Solid icons in my actions and that's it. I may use your suggestion on this one.

On the other hand, I'll definitely start to add another column to my standard list to hold inline actions. I tend to use RowNumber but a dedicated one for it will be better. Just curious, since this is not a field with data, any reason to have a real column over a VC?

Finally, since we have talked about this with Matt multiple times so that is not a secret or something, here you have my list of must-have columns for all tables that may be helpful for you:

Field Purpose
ID Primary key
Label AppSheet label column
Update To trigger appformulas
Created by Initial Value of, generally, the userid
Created in Initial value of HERE()
Created at Point's to the Modified at on Initial so that I have a way to know if the user is creating the record or changing it because when creating it it would have the same value as Modified at. If not needed, NOW() will suffice
Modified by Same as Created by but on AppFormula
Modified at ChangeTimeStamp
Pseudo id Helps to check whether a record is unique or not in the context of the table by using something similar to a computed key
Times edited ChangeCounter
Flags EnumList to add flag words. This works the same as having 1000 flag columns like "Editable?", or "Approved?" since you can just add those texts in the list and then check against the column using IN()
Hope this helps 🤙🏽

This is getting interesting. I'm going to reread it carefully. Your experience is vast, much greater than mine, and the reason is that you have been working with AppSheet for a long time, Oscar @SkrOYC . I appreciate your contribution to this. The idea is to move away from this being just an essay and turn it into a convention. In fact, I'm going to try to include your methods in this protocol, so that we can unify some criteria. "The one who strikes first strikes twice" is what they say where I live. So your contribution is very important.

I want to add something important:

"Do not fix what works."

If you have already created apps with other methods, and if you are doing other things, do not waste time; apply new ways of working for the same benefit, only in new creations. This will make the protocol more easily accepted. Keep in mind that this is not the ultimate truth but a way we will enrich together, dynamically, day by day, as AppSheet continues to update. Believe me, there will be things that will lose their effect in the future; for example, when AppSheet changes the value of fields in expressions as they change in the database, the show if expressions will not be reset. And many more things like this. This is just the beginning.

If I want to ask you something Oscar, You use the name ID for the Key field, I use Row ID because AppSheet DataBase creates a unique Row ID field. The million-dollar question is:

Is it convenient to use that automatically created field by AppSheet, or is it better to create a new one?

Let's see. My response would be to use it, but of course, when migrating an app from Google Sheets to AppSheet DataBase, we would have an issue with generating a duplicate field. However, when working directly in the AppSheet DataBase, it works. Nevertheless, I'm open to changing the convention.

 

Regarding your question "a real column on a virtual column" for actionn, I don't know... I actually try to avoid VC at all costs. But I have no other reason Oscar

Im gonna reply in english since this will benefit the conversation to all people here.

I don't use AppSheet Databases and, to be honest, I don't have plans to do it in the near future, unless there is a client that comes to me asking me to strictly use it. In that case I'd try to convince them to not do it anyways...

So, since I don't know how it works, I don't know if what you are saying is actually possible. But, if it is, I'd recommend to do it, use a method that help you to move away from AppSheet Databases if needed, like when upgrading to SQL.

Any platform that locks you in with some "feature" is a platform to be cautious about, IMO.

Aside from that, I'd suggest you to use UNIQUEID("UUID") since this is a standard method used outside AppSheet as well.

Also, I'd like to note that my methods are highly influenced by Postgres and it's naming conventions, as well as Supabase, which is the DaaS that I'm using.

(Apr 25, 2024 - Updated)

Top Labels in this Space