ИМХО, первый пример - это больше вопрос о том, как пользователю представляются катастрофические сбои.В случае, если кто-то делает что-то действительно глупое и не устанавливает activeGames ни на одно, большинство языков генерирует исключение типа NullPointer / InvalidReference.Если у вас есть хорошая система для выявления ошибок такого рода и их элегантной обработки, то я бы сказал, что вы полностью исключите эти охранники.
Если у вас есть достойный набор юнит-тестов, они обеспечат огромныеесть определенная уверенность в том, что проблема такого рода не ускользает от машины разработчиков.
Что касается второго, то, от чего вы действительно защищаетесь, это состояние гонки.Что если метод doStuffToMakeFooTrue () никогда не делает foo истинным?Этот код в конечном итоге попадет в землю.Вместо того, чтобы рисковать, я обычно помещаю такой код в таймер.Если ваш язык имеет замыкания или указатели на функции (если честно, не уверен насчет Python ...), вы можете скрыть реализацию логики синхронизации в хорошем вспомогательном методе и вызывать его следующим образом:
withTiming(hmph, 30) // run for 30 seconds, then fail
Еслиу вас нет замыканий или указателей на функции, вам придется делать это далеко и везде:
stopwatch = new Stopwatch(30)
stopwatch.start()
while stopwatch.elapsedTimeInSeconds() < 30
hmph()
raise OperationTimedOutError()