Сегодня мы поборолись со следующим куском кода:
(defn- consume [& {:keys [timeout] :or {timeout (:request-ms (config :bus))}}] (let [pool (safe-kc-messages (get-instance) :timeout timeout)] (map process pool))) (defn- process-messages [] (loop [] (if-let [msgs (consume)] (log/info (System/currentTimeMillis) ": OK") (Thread/sleep (:reconnect-ms (config :bus)))) (recur)))
Девелопер впервые видит эту штуку, хотя этому сервису как минимум два года.
Начали дискуссию с пункта:
«— Почему этот код каждый раз спит?» (что означает «вне опроса»)
Уверен, что этот код вообще не спит. Обычно.
Но это было так любопытно, что продолжаем шаг за шагом разворачивать его (девелоперскую) мысль:
« — Почему вы каждый раз думаете, что код спит?»
« — Потому что ‘consume’ всегда возвращает не пустое значение»
« — Н-е-е-е-е. Но почему он Спит?!»
«— Потому что «если-пусть» всегда получает «истину» и, таким образом, вызывает «сон»»
Вау... Слишком много чепухи, чтобы быть правдой...
«— О’Кей… Давайте вспомним описание «если-давайте» и найдем там истинные и ложные ответвления»
Пару минут мы бились с абсолютно правильным кодом, но в конце концов сошлись на том, что здесь все просто отлично.
Первоначальный дизайн был непробиваемым — если в шине нет сообщений, он спит в опросе, когда получает исключение — он спит вне опроса, а затем снова подключается. Прохладный.
«— Но тут еще жучок.»
Уфффф…
«— Где ошибка?!»
«— Этот код никогда не спит вне опроса»
Вау-вау-вау… Он абсолютно прав! Этот сервис настолько старый, что до сих пор баг уже исправлен практически везде, и действительно не спит вне опроса. Потому что есть `(пусть…)`, но не `(когда-пусть…)`.
Почему это так важно?
С точки зрения бизнеса это здорово и реально круто, что такая ситуация произошла.
Хороший инженер не всегда сможет сразу описать проблему, и это нормально. Но его подсознание уже уловило саму проблему, а также ее природу.
Мы всегда должны пытаться понять кого-то, стараться «думать в его шкуре» — иначе мы всегда будем жить в мире «бесконечной гибкой разработки».