Pull to refresh

Comments 14

Добавление проверки на длину documents в фукнции convertMongoDocumentsToProducts, снимет необходимость лишней проверки на ошибку. Например, так:

func (dao *DAO) FindProductsByIDs(ids []ProductID) ([]*Product, error) {
    if len(ids) == 0 {
        return nil, nil
    }
    dbQuery := {"_id": {"$in": convertProductIDsToStrings(ids)}}
    documents, err := dao.mongoCollection.find(dbQuery)
    return convertMongoDocumentsToProducts(documents), err
}

если:

func convertMongoDocumentsToProducts(documents []Document) []*Product {
    if len(documents) == 0 {
        return nil
    }
}

Конечно, если dao.mongoCollection.find возвращает zero-value при возврате ошибки.

Энтропия на том же уровне, а пользы больше.

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

Скорее всего вы правы, я обратил внимание лишь на энтропию в контексте увеличения кода и добавления условного оператора. Если взглянуть в контексте обращения к БД, то стоит ли обсуждать пример, очевидно, что такая проверка необходима.

Вместе с тем, кажется, что слой dao должен быть достаточно умен, чтобы понять, что запрос не вернет результата.

Dao не один работает с базой, так что один и тот же запрос, выполненый через пару минут, может вернуть различные данные.

Правильная статья, спасибо!

Но всё же хотел бы немного поспорить относительно этого места:

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

А чуть выше Вы сами же пишете, что этих решений нам приходится принимать очень много во время работы (и это реально так). Проблема в том, что излишне детальный анализ каждого маленького шага очень сильно замедляет работу и, скажем так, отравляет сомнениями. Сам через такое проходил порой.

Подумайте над таким подходом: что, если параллельно, в двух независимых потоках, добавлять в код фичи и бороться с энтропией? Получится, что в каждом из потоков надо будет принимать меньше решений. При реализации фичей меньше думать о глобальной картине, а при чистке не думать о фичах, только лишь выдерживать соблюдение инвариантов. Кажется, так получилось бы и качество держать на уровне, и не скатиться в analysis paralysis при работе над сложными фичами.

Много кода пишется на автомате и это ок, так что мест, где реально принимается какое-то решение, чаще всего не так много. Так что это не буквально 100% рабочего времени 🙂

При реализации фичей меньше думать о глобальной картине – это мне не нравится. Как только мы принимаем какое-то решение о том, как фича будет реализована, мы невольно начинаем мыслить в этой принятой парадигме. Менять получившийся код может оказаться не просто затруднительно по времени — сама идея более удачного решения может потеряться или перестать выглядеть логично.

А чищу код я чисто на автомате, конечно, исключительно на языке инвариантов. Но это возможно только если он изначально написан неплохо 🙂

Я подумал на досуге: возможно, у нас просто разный экспириенс в этой области. Когда работаешь над относительно некрупными проектами и в относительно небольшой команде, продумывать последствия наперёд вполне реально, и это не будет сильно замедлять.

Но вот несколько лет назад приходилось мне работать над java-монолитом в ~1M SLOC, с десятками взаимосвязанных модулей внутри, с несколькими командами, которые эти модули развивают (человек 50 примерно), с историей изменений лет в 10-15. Прикольно было - но пришлось серьёзно задуматься над тем, как же так работать, чтобы задачи закрывались за разумное время. Тогда и открыл для себя малые решения: мы их принимаем очень много, и каждое имеет свою цену. И если мы хотим поддерживать высокий темп разработки, то вариантов не так уж много. Надо уменьшать либо стоимость принятия решений, либо их число.

Потому-то такой наброс-намёк и написал в изначальном комментарии.

Я работаю над проектом > 1M LOC на Go)

И ещё одна мысль: Вы совершенно верно обратили внимание, что мы принимаем очень большое количество малых решений относительно кода в процессе работы. Как связать данные друг с другом, как назвать переменные, сколько параметров перекинуть в метод, сделать наследование или композицию классов, и т.д. и т.п. Многие эти решения оставляют свои следы в коде. А эти следы, в свою очередь, влияют на последующие решения.

Подвожу к ключевому моменту. Люди. Очень. Разные. В одних и тех же ситуациях мы будем принимать совершенно разные решения, опираясь на собственный предыдущий опыт (который существенно отличается). Даже один и тот же человек может легко менять свои привычки и подходы. Например, если прочитает Вашу статью и проникнется важностью борьбы с энтропией. А другой, кто её не читал, будет проникнут важностью чего-то другого - и свои малые решения будет принимать иначе. Представим теперь, что эти два гипотетических человека работают над одним общим кодом. Вопрос: что происходит с энтропией в этом коде?

Что угодно может произойти! Поэтому в проекте должен быть СТО/техлид, одной из онсовных задач которого будет выработка и enforcement общих подходов. А отдельно взятому разработчику нужно стараться обращать внимание на то, какие привычки и подходы доминируют в кодовой базе вокруг него, и либо принимать их, либо убеждать всех вокруг, что нужно делать по-другому.

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

Одно из проявлений энтропии, например, - называть одни и те же сущности разными именами в коде. Грешат все и везде. Типа «да какая разница, все равно же статически верифицируется связность». А вот разница колоссальна (особенно для того, кто в будущем код будет читать или дописывать).

Еще заметил эмпирически, что конструкции if значительно увеличивают энтропию и багорискованность. А вот паттерн наследования - увеличивает ее значительно, значительно меньше. Поэтому везде, где чешутся руки написать иф, хорошо бы подумать, а нельзя ли обойтись наследованием или хотя бы таблицей.

Насчет продуктов понял ваш тезис только вот "а немногие места, где надо обработать скрытые товары" может оказаться что таких мест много, и даже пользователям надо показывать такие товары только с подписью "нет на складе" и в таком случае флаг будет лучше. И еще, если мы делим на 2 сущности то при добавлении новых полей или изменении старых неопределенность увеличилась. В целом конечно нужно думать постоянно, иметь полную статистику по проекту, и точное тз или спецификацию.

С точным ТЗ в продуктовой разработке сложновато, потому что никто не умеет глядеть в будущее, увы)

Не к месту тут энтропия. И определение энтропии из термодинамики.

Является ли непредсказуемость энтропией? Нет, энтропия не синоним хаоса, а хаос не синоним непредсказуемости или неопределённости.

Стремятся ли письма разлететься кто куда, не по адресу? Нет, существует вероятность в следствии программной ошибки, внешних или внутренних факторов, что письмо не дойдёт до адресата.

Sign up to leave a comment.