When is the server called in this code?

My code is all working well. I’m just trying to understand, that’s all! In this code block:

          game_state = anvil.server.call("update")
          if game_state is None:
            return
          if self.player_color == "green":
            if game_state["GreenHand"] != self.hand:
              self.hand = anvil.server.call("get_hand", "green")
          if self.player_color == "blue":
            if game_state["BlueHand"] != self.hand:
              self.hand = anvil.server.call("get_hand", "blue")
          if game_state["Board"] != self.model:
            self.model = game_state[
              "Board"
            ]  
          if game_state["IsGreenTurn"] != self.is_green_turn:
            self.is_green_turn = game_state["IsGreenTurn"]

The first line retrieves a row from the database: return app_tables.board_state.get(id=1). Subsequent lines retrieve values for individual cells or fields from the row. Is the server called just once (first line)? Or is it called with every game_state['something'] line?? (If it’s called repeatedly, there’s really no need for the first line then, right?)

And, just out of curiosity, if this was something more than someone learning to program, would you use try...except blocks to prevent exceptions? If so, is it enough to have one block around all the code, or do you surround every server call? (Again, everything is working fine, I’m just learning.)

Thank you for being my teachers :slight_smile:

The short answer to the title question is, “it depends”.

It depends, in part, on the types of values in these columns.

Note that you can use features of the Accelerated Tables Beta to explicitly state which columns to physically retrieve, thus eliminating any questions about that, for the foreseeable future.

That really depends on the design philosophy of your program.

User-interface code often orchestrates effects across multiple components, so it can be rather finicky, with one missing step breaking important behavior or user feedback. This code can be interrupted by timers and by user interactions, but it resumes thereafter, so you can be sure that its cleanup code (if any) actually executes after the interruption. Thus, steps may be delayed, but are usually not skipped altogether.

To get the same effect with a server call, my try-except blocks exist on the server side, translating the exceptions I can expect to handle into client-meaningful error codes, which are then passed back to the client. The client can then deal with those error conditions in whatever timeframe and manner it sees fit, via ordinary if statements.

I find this kind of GUI support code much easier to reason about, than having my try-except blocks on the client. The only Exceptions that this code should see, would be the kind that halt the App as a whole, and for those, there is a global handler available. See Error Reporting.

However, if the server call is in non-GUI code (an ordinary client module), then it’s usually a bit less finicky, and I’d consider wrapping the server call in try-except on the client.

Ultimately, it really depends on your App’s error-handling philosophy, i.e., how you want your code to look and behave.

Thank you, Phil. Good advice. I didn’t know about accelerated tables (which sound like someday this’ll be the default), nor the global error handling. I’m going to just wrap the whole thing in a single try/except. I really appreciate you taking the time to respond, especially with such a long, helpful response. Thank you again.

1 Like