Тема: Таблиці істинності для рефакторінга
Хочу трохи поділитися досвідом. Насправді нічого особливого, але комусь з новачків (і не тільки) може стати в нагоді.
Отже, стрів ось такий код (для узагальнення на Python):
def do_some_action(is_red):
is_blue = False
try:
#тут шматок на ~10 рядків, що з різних функцій, файлів і БД отримує булеве значення is_blue
except:
#на випадок якогось збою
pass
#тут найцікавіше
if is_blue and not is_red:
way_one()
else:
way_two()
if not is_blue and not is_red:
open_box()
put_something(False)
close_box()
elif is_red:
open_box()
put_something(True)
close_box()
І мені треба було змінити поведінку do_some_action. Ну тобто іноді там way_one, іноді way_two, іноді open_box з close_box взагалі не спрацьовує. А мені треба, скажімо, щоб після way_two викликалася ще одна функція після всіх open_box та close_box, наприклад, get_back_from_way_two(). Але тільки якщо ці open_box і close_box застосовувалися. І не хочу писати get_back_from_way_two() двічі.
Цілком можливо, що ви подивитеся на цей код і скажете: "та тут все зрозуміло!". Ну, ви молодець. Я не такий, мені треба подумати. Функція, вочевидь, лінійна при будь-якій комбінації is_blue і is_red. Давайте розпишемо ці комбінації і які викликаються функції:
is_blue is_red
True True way_two, open_box, put_something(True), close_box
True False way_one
False True way_two, open_box, put_something(False), close_box
False False way_two, open_box, put_something(True), close_box
Оп-па. Так way_one викликається тільки в одному випадку - при is_blue and not is_red, і більше нічого тоді не викликається. Одразу робимо розгалуження:
if is_blue and not is_red:
way_one()
else:
way_two()
if not is_blue and not is_red:
open_box()
put_something(False)
close_box()
elif is_red:
open_box()
put_something(True)
close_box()
Тепер бачимо, що в усіх трьох інших шляхах викликаються і open_box, і close_box. Виносимо їх з гілок:
if is_blue and not is_red:
way_one()
else:
way_two()
open_box()
if not is_blue and not is_red:
put_something(False)
elif is_red:
put_something(True)
close_box()
Мені цей код вже дуже подобається, але це ще не все. Параметр put_something дорівнює True тільки у тих гілках, де is_blue і is_red мають однакове значення, а в третій він False - тобто він дорівнює is_blue==is_red:
if is_blue and not is_red:
way_one()
else:
way_two()
open_box()
put_something(is_blue==is_red)
close_box()
#ну і додамо вже нашу функцію, як і треба було
get_back_from_way_two()
Цей код повністю еквівалентний початковому. Зате наскільки зручніше із ним працювати, правда?