пятница, 18 ноября 2011 г.

Текущий проект

Привет! Как я и обещал в комментариях к прошлому посту, расскажу немного о том, чем в данный момент занимаюсь.

Собственно, где-то с конца лета я помогал питерским ребятам делать социалку, однако как-то не срослось, через какое-то время устал и ушёл. Совсем не комфортно, когда ты знаешь, что ты кому-то должен что-то и не имеешь над этим контроля.

Ну а делать что-то нужно, без дела слишком уж уныло становится через какое-то время. Поэтому решили с друзьями делать тоже социалку. Тем более что у них тоже были идеи и они мне понравились :).

Плюс ко всему, есть мотивация делать, за нами наблюдает одна большая компания, которая каждую неделю смотрит, что сделано, мы рассказываем, чего делали и чего будем делать дальше. И хоть мы на данный момент сделали не так уж и много (практически ничего), мы движемся, составляется кое-какая документация и всё хорошо.

Игра про магию. Больше толком ничего не расскажу. Мы ориентируемся на социалку, однако по стилю игры это не совсем «тупо нажал, получил пряник, подарил пряник другу», там даже есть онлайновые PvP-битвы между игроками. Ну и их заменители, если с онлайном не ок.

Если будет чего рассказать по архитектуре, или ещё по чём-нибудь, то напишу. Тут я не ограничен никакими неразглашениями.

P.S. Эти картинки — скриншоты из экрана создания персонажа, если что :)

суббота, 12 ноября 2011 г.

Определение места badmatch при вызове одинаковых функций

Итак, допустим, что у вас есть вот такой код:

sometimes_not_ok(42) ->
  not_ok;
sometimes_not_ok(_) ->
  ok.
test() ->
  ok = sometimes_not_ok(13),
  ok = sometimes_not_ok(42).
Функция sometimes_not_ok/1 возможно говорит с бд, или ещё чего-нибудь такого и может выбрасывать исключения/возвращать значения, которые никак не характеризуют аргументы, переданные ей.

У нас есть 2 пути, как сделать так, чтобы мы знали, в каком месте случился фейл. Первый из них заключается в том, чтобы обернуть всё в case'ы:


case sometimes_not_ok(13) of
  ok ->
    case sometimes_not_ok(42) of
      ok ->
        continue_here;
      not_ok ->
        not_ok_processing
    end;
  not_ok ->
    not_ok_processing
end.
Однако согласитесь, код при этом станет выглядеть ужасно. А если вам нужно будет поменять две строчки местами? А если у вас сотня таких вызовов? Да и это какое-то дефендное программирование выходит, у эрланга несколько другая концепция.

Второй же наш вариант, использовать try/catch:

try
  ok = sometimes_not_ok(13),
  ok = sometimes_not_ok(42)
catch
  error:{badmatch, not_ok} ->
    not_ok_happened
end.
Уже намного лучше. Первоначальный код виден, его можно легко поправить, нет кучи вложенных условий. Однако... когда произойдёт {badmatch, not_ok}, мы не будем знать, на какой строке он произошёл, там где мы передали 18, или же 42? А вот нам позарез нужно выполнять там какие-то действия, если не ок.

Ну и мне пришло в голову, что можно просто обернуть вызов функции в tuple. Вот так:

try
  {_, ok} = {first, sometimes_not_ok(13)},
  {_, ok} = {second, sometimes_not_ok(42)}
catch
  error:{badmatch, {first, not_ok}} ->
    not_ok_happened_first;
  error:{badmatch, {second, not_ok}} ->
    not_ok_happened_second
end.
И тогда мы с лёгкостью можем определить, в каком из мест у нас badmatch. Конечно, внешний вид кода стал немножечко не таким красивым, но ведь согласитесь, так намного лучше, чем с кучей case'ов?

Может быть, конечно, мой «способ» всем давно известен, тогда уж ладно. Но мои знания всё равно растут :).