1 Востаннє редагувалося koala (29.01.2018 23:07:30)

Тема: Таблиці істинності для рефакторінга

Хочу трохи поділитися досвідом. Насправді нічого особливого, але комусь з новачків (і не тільки) може стати в нагоді.

Отже, стрів ось такий код (для узагальнення на 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()
  

Цей код повністю еквівалентний початковому. Зате наскільки зручніше із ним працювати, правда?

Подякували: FakiNyan, ReAl, /KIT\3

2 Востаннє редагувалося FakiNyan (29.01.2018 23:17:56)

Re: Таблиці істинності для рефакторінга

піду зара до кімнати відпочинку, поки буду там сидіти, перегляну оцю вашу писанину, сподіваюсь, що це щось цікаве...
upd:
в мене подібних шматків коду була сила-силенна, то я вирішував проблема методом тику, тепер буду малювати таблицю істинности, дякую!
воно мені чимось нагадує спрощення в математиці, виносимо за дужки, скорочуємо там..