shri-2015-org / 666

666 team's chat =>
http://anonym.club
4 stars 3 forks source link

feature-validation #43

Closed tempname11 closed 9 years ago

tempname11 commented 9 years ago

Довольно массивный PR, много нового utility кода. Честно говоря, получилось больше, чем я ожидал и меня немного беспокоит, что я написал велосипед, который никому не нужен 🙀. В случае чего, я готов к варианту, что мы откажемся от этого PR (или возьмем только куски кода), если будет понятно, что задуманное чересчур сложно для понимания/отладки/поддержки.

Тем не менее, здесь всё то, о чем я говорил в понедельник и в #36. Попробую рассказать про плюшки:

Инварианты

Инварианты -- это что-то вроде типов, но чуть более общие. Они просто умеют проверять значения на соответствие какому-то критерию. Например, Str проверяет, что значение это JavaScript-строка. Пока что не написанный UID мог бы проверять, что значение -- это некая правильно сформированная строка вроде 'Dy9xBwJQZpfaLH7_AABK1442603362743'

Их можно использовать:

Сейчас они реализованы через пресловутые PropTypes, однако это оказалось немного тяжеловесно и для упрощения кода я предполагаю переписать их реализацию.

Аннотации функций

Аннотированная функция проверяет инварианты для входящих и выходящих значений каждый раз, когда ёе запускают.

annotate

import { annotate } from '~/common/utils/annotation';
import { Str } from '~/common/utils/invariants';

const concat = annotate(Str, Str)(Str)((s1, s2) => s1 + s2);

concat будет автоматически проверять, что оба аргумента и результат -- строки, и кидать ошибку, если это не так.

annotated

Просто сахарок. Использует ES7 декораторы. К сожалению, для использования декоратора, обычную функцию приходится завернуть статичным методом в класс.

import { annotated } from '~/common/utils/annotation';
...
export default class Builder {
  @annotated(Socket, Role, Protocol, FuncMap)(FuncMap)
  static build(socket, role, protocol, receiveCallbacks) {
    ...
  }
}

Предлагаю использовать аннотированные функции (+ jsdoc) для документации (#16) кода.

Транспортное API, описанное в коде (Protocol)

Начал переводить https://github.com/shri-2015-org/666/wiki/API-server Выглядит это как-то так.

export const Message = Shape({
  mid: Str,
  uid: Str,
  text: Str,
  time: Num,
});

export const User = Shape({
  uid: Str,
  name: Str,
  avatar: Str,
});

...

export const protocol = {
  login: exchange(UP,
    Shape({uid: Str}),
    User
  ),

  message: notification(DOWN,
    Message
  ),

  ...
}

Протокол описывает то, как данные могут ходить "вверх" и "вниз" между клиентом и сервером.

Notification

notification(direction, invariant) означает, что данные могут быть посланы в направлении direction (UP: на сервер, DOWN: на всех клиентов), и не требуют ответа. Данные должны соответствовать инварианту invariant.

Exchange

exchange(direction, requestInv, replyInv) означает, что данные могут быть посланы в направлении direction (UP: на сервер, DOWN: одному клиенту) с инвариантом requestInv, и на это должен быть ответ в противоположном направлении с инвариантом replyInv.

Builder

Cм. код на annotated выше.

Протокол используется (как простые данные) в common/transport/builder.js для построения транспортной прослойки. Если и сервер, и клиент будут использовать Builder, то гарантируется, что они будут полностью совместимы. Пока что я не успел адаптировать сервер.

...

Возможно, я про что-то забыл, но уже просто не успеваю написать. Критика приветствуется.

tempname11 commented 9 years ago

Закрыто, потому что мы решили использовать jsdoc и, возможно, flow. Часть про transport builder решили оставить с вырезанными инвариантами.