Code Smell 230 - Schrödinger Code

Maxi Contieri - Nov 4 '23 - - Dev Community

Your code is dead and alive

TL;DR: Look carefully for race conditions

Problems

Solutions

  1. Avoid race conditions

  2. Avoid global variables

  3. Use proper synchronization

Context

Schrödinger code is code that can be in two different states at the same time, but the state of the code is not determined until it is executed.

This can happen when the code contains a race condition, or when the code depends on the state of a global variable that can be changed by other threads or processes.

Sample Code

Wrong

import threading

cats_alive = 0

def thread_1():
  cats_alive += 1

def thread_2():
  cats_alive -= 1

if cats_alive > 0:
  feedThem()

# The value of cats_alive is indeterminate, 
# so the code can be in either of the two states:
#
# 1. cats_alive > 0 and feedThem() is called.
# 2. cats_alive <= 0 and feedThem() is not called.

Enter fullscreen mode Exit fullscreen mode

Right

import threading

lock = threading.Lock()
cats_alive = 0

def thread_1():
  with lock:
    cats_alive += 1

def thread_2():
  with lock:
    cats_alive -= 1

if cats_alive > 0:
  feedThem()

# With the lock, the two threads cannot access 
# the `cats_alive` variable at the same time.
# This means that the value of `cats_alive` is always determined, 
# and the program will not exhibit Schrödinger code behavior.

Enter fullscreen mode Exit fullscreen mode

Detection

[X] Manual

Make code reviews on concurrent code

Tags

  • Concurrency

  • Globals

Conclusion

To avoid Schrödinger code, avoid race conditions and avoid depending on the state of global variables that can be changed by other threads or processes.

If you need to use a global variable in your code, ensure it is correctly synchronized.

Relations

Disclaimer

Code Smells are my opinion.

Credits

Photo by Yerlin Matu on Unsplash


The last thing you wanted any programmer to do is mess with internal state

Alan Kay


This article is part of the CodeSmell Series.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .