Хаос всегда увеличивается.
Оно растет непрерывно и неизбежно.
Вот что говорит второй закон термодинамики: в любой закрытой системе энтропия – мера хаоса – возрастает до тех пор, пока не достигнет термодинамического равновесия – состояния полной неопределенности, когда ничего нельзя предугадать и все ведет себя крайне беспорядочно.
Мы, живые организмы, не являемся замкнутыми системами и сдерживаем рост энтропии внутри себя, увеличивая ее снаружи – насколько можем.
А софтверные проекты имеют много общего с нами: они тоже вынуждены тратить внешние ресурсы (усилия разработчиков, процессоры на накладные абстракции), чтобы сдерживать постоянно растущую энтропию — иначе в какой-то момент они теряют способность быстро адаптироваться к меняющейся реальности и умереть.
Какаду воспринимают тезис об увеличении энтропии снаружи слишком буквально.
Что такое энтропия в контексте программного кода? Википедия дает восемь различных определений энтропии в разных науках, и все они имеют ограниченную применимость в нашем случае, поэтому я не берусь дать формализованный ответ на этот вопрос.
Но при принятии архитектурных решений и написании кода я все чаще думаю о последствиях с точки зрения энтропии, поэтому приглашаю вас в свой чудесный мир сомнительных аналогий.
«Антропность и ценность программных компонентов»
Мир вокруг нас страшен и непредсказуем, и мы постоянно придумываем решения, чтобы уменьшить эту непредсказуемость.Мы готовы за это платить, и многие ИТ-продукты представляют собой не что иное, как услуги по снижению энтропии.
Хотите заказать товар онлайн, но боитесь, что придет не тот товар? Здесь расположены маркетплейсы со своими складами, гарантиями и арбитражем.
Вы хотите отправить своим пользователям информационный бюллетень по электронной почте, но у всех поставщиков услуг электронной почты свои правила, и вы не уверены, что ваше письмо не попадет в папку «Спам»? Вот вам почтовые сервисы.
Хотите отправить товар почтой, но способов доставки так много, вам нужно взаимодействовать с разными компаниями на разных этапах, и вы не можете определить, какой процент ваших посылок вообще придет? Вот логистические решения для вас.
Это также верно и на уровне кода.
Насколько предсказуем внешний API? Он может лежать там, может стоить пятьсот, за него могут забыть заплатить, но мы не хотим каждый раз обрабатывать все эти случаи в коде, поэтому создаем уровень абстракции, который берет на себя эти проблемы.
Для остальной части кодовой базы осталось всего два состояния: либо получен корректный результат, либо выброшено исключение.
Была ли какая-либо проверка? Был ли ответственный менеджер уведомлен об истечении срока подписки? Это больше не проблема для вызывающего кода.
Соответственно, ценность компонентов программного обеспечения можно оценить как разницу в энтропии, которую они вносят. Тонкие клиенты более надежны и гибки, но предоставляют меньшую ценность.
Сложные абстракции сложно писать, они требуют постоянного обслуживания и мониторинга, но могут принести гораздо большую пользу.
Если у вас есть большой и сложный внутренний компонент, который облегчает жизнь другим разработчикам, будь то движок MapReduce или распределенная очередь, вы можете думать о себе как о малом бизнесе внутри бизнеса, и чем больше хлопот он требует, тем ценнее он становится.
на.
Больше ответственности - больше бюджет на содержание и развитие - выше разряд руководителя (шутка).
Энтропия и качество кода
Когда мы решили архитектурные вопросы и пишем конкретный код, мы имеем дело с определённым количеством бизнес-субъектов, будь то продукты, магазины, пользователи, посты и так далее.Как правило, большинство сущностей имеют то или иное состояние: пользователь может быть активным или забаненным, публикация может быть видимой или скрытой, товар может быть на распродаже или отсутствовать в наличии.
Помимо этого, обычно существует какое-то глобальное состояние.
Сейчас лето и вам нужно показывать больше санок в результатах поиска? Сейчас чемпионат мира и нужно, чтобы посты о футболе давали больше впечатлений? Неопределенность ждет нас повсюду.
Рост количества факторов, количества сущностей, рост этой самой неопределенности — энтропии — парализует разработчиков.
Единственный способ после нескольких лет разработки сохранить кодовую базу в поддерживаемом состоянии — это постоянно думать о том, как минимизировать рост энтропии при добавлении нового кода, и регулярно предпринимать усилия по ее сокращению — рефакторинг, удаление старого, развивать новые слои абстракции и ценные (в смысле предыдущего).
раздел) Программные компоненты.
Давайте рассмотрим примеры разных решений одной и той же задачи с разной энтропией.
Допустим, у нас есть продукты в нашем сервисе и компонент, который может извлекать их из базы данных.
Наш проект жив и развивается, тип Product используется во многих местах, все идет хорошо.type Product struct { ID ProductID Name string Image *image.Image .
} type ProductManager interface { GetProduct(ProductID) (*Product, error) }
И вот в один прекрасный день мы решили, что нужно научиться скрывать некоторые товары с сайта.
Может быть, их нет в наличии, может быть, они вышли из моды, может быть, что-то еще.
Как это сделать? Хм, ну, очевидно, вам просто нужно добавить флажок в Product: type Product struct {
ID ProductID
.
Hidden bool
}
С точки зрения энтропии проекта в целом это катастрофический изменять.
Везде, где обрабатываются товары (то есть вообще почти везде), неопределенность увеличивается вдвое: к состоянию, где обрабатывается «обычный» продукт, добавляется состояние со скрытым продуктом.
Теперь нужно проверять этот флаг везде, даже там, где, на первый взгляд, это не нужно - ведь очень скоро новые возможности для скрытых товаров перестанут выкатывать, состояние объектов в базе данных в целом устареет, инварианты перестанут соблюдаться и т.д. Вы перестали продавать товары без картинок и написали код, который означает, что картинка всегда ненулевая? Устаревшие продукты не волнуют. Хорошей альтернативой будет создание в менеджере отдельного типа и метода для скрытых товаров.
type Product struct {
ID ProductID
Name string
Image *image.Image
.
} type HiddenProduct struct { ID ProductID LastName string LastImage *image.Image .
HiddenAt time.Time
HiddenBy AdminID
}
type ProductManager interface {
GetProduct(ProductID) (*Product, error)
GetHiddenProduct(ProductID) (*HiddenProduct, error)
}
Теперь весь существующий код, написанный в предположении, что товар отображается на сайте, доступен для покупки и с ним в целом всё хорошо, продолжит функционировать с той же степенью уверенности, что и раньше, и мало мест, где нужны скрытые продукты.
подлежащий обработке может грамотно справиться с этим делом или переключиться на работу с интерфейсом.
Энтропия и оптимизация кода
По самому своему определению информационная энтропия — показатель того, насколько эффективно можно сжать данные (например, с помощью алгоритма Хаффмана).Насколько эффективно можно обрабатывать данные? В мире идей программирование заключалось бы в тщательной реализации оптимального алгоритма решения задачи, и на этом все бы и закончилось.
В реальном мире мы продолжаем оптимизировать высоконагруженные фрагменты кода снова и снова.
А качество оптимизации обратно пропорционально энтропии: чем меньше неопределенности мы испытываем относительно входных данных и среды выполнения программы, тем лучше мы можем оптимизировать код. В условиях полной неопределенности оптимизации невозможны — потому что чудес не бывает.
Давайте посмотрим на этот код. func (dao *DAO) FindProductsByIDs(ids []ProductID) ([]*Product, error) {
dbQuery := {"_id": {"$in": convertProductIDsToStrings(ids)}}
documents, err := dao.mongoCollection.find(dbQuery)
if err != nil {
return nil, err
}
return convertMongoDocumentsToProducts(documents), nil
}
С ним вроде все в порядке.
Но вам не терпится поставить это в самом начале? if len(ids) == 0 {
return nil, nil
}
? Вне контекста это сомнительная оптимизация.
Он добавляет пару инструкций абсолютно ко всем вызовам методов, но оптимизирует достаточно узкое подмножество, хотя и существенно.
Кажется редким случаем, чтобы кто-то вызывал метод с пустым списком идентификаторов.
Однако мы с коллегами увидели, что в реальности из-за большого количества логики, связанной с фильтрацией сущностей, такие вызовы происходили довольно часто — настолько часто, что мы начали наблюдать дисбаланс нагрузки на шард базы данных, на который отправлялись такие запросы.
тот маленький уверенность позволило нам оптимизировать это место, хотя эта оптимизация (как и все оптимизации) не является универсальной.
То же самое и с любой эвристикой.
Эвристика — это всегда опора на некоторую существующую определенность, в отличие от ситуации полной неопределенности, когда эвристика ничего не улучшает.
Вместо заключения.
Энтропия и затраты на разработку Если бы мы могли создавать ценность без затрат, мы были бы миллиардерами.
Но в мире постоянной конкуренции семи миллиардов человек все простые пути, конечно, уже пройдены.
Это означает, что любая созданная ценность будет стоить нам ресурсов.
Первый раздел этой статьи теперь можно прочитать с точностью до наоборот: чем больше вы планируете снизить энтропию с помощью своего программного компонента, тем больше гарантий вы хотите дать его пользователям, тем дороже вам это будет стоить — вы не можете всегда будьте уверены даже в рентабельности! Самый простой код можно записать как обычную функцию в файле utils. Для более сложных понадобится менеджер с конструктором.
В какой-то момент потребуется внешний источник конфигурации.
Затем сохраните состояние в постоянном хранилище.
Дальше — микросервис, серверы, доступ к сети, дежурный инженер и так далее.
Хаос царит. Но на каждом этапе продумывания архитектуры и написания кода мы принимаем бесчисленное множество мелких решений, которые могут повлиять на энтропию внутри и за пределами проекта.
Как узнать, какой из них правильный? Вот несколько вопросов, которые я лично стараюсь задать себе в поисках ответа:
- Насколько неопределенность снижает неопределенность компонент, который я пишу? Могу ли я дать больше гарантий без дополнительных затрат? Могу ли я дать чуть меньшую гарантию при значительном снижении затрат?
- Соответствует ли моя оценка времени, которое потребуется на разработку этого компонента, тем преимуществам, которые мы от него ожидаем? Если это занимает слишком много времени, стоит ли это делать? Как вообще эта проблема решается в других местах? Если слишком быстро, то точно ли я все учел?
- Насколько увеличится количество состояний программы из-за моего изменения? Могу ли я локализовать это повреждение?
- Насколько я ясно понимаю источник уверенности, который позволяет мне провести эту оптимизацию? Будет ли эта уверенность с нами завтра? Можно ли выжать из него больше?
Теги: #программирование #Управление проектами #разработка #Go #дизайн и рефакторинг #второй закон термодинамики #энтропия #попугаи #люблю попугаев что с меня взять
-
Учет
19 Oct, 24 -
Опыт Создания Интернет-Сми От Юрия Синодова
19 Oct, 24 -
Андрариум
19 Oct, 24 -
Voxxed Days Минск
19 Oct, 24 -
Неужели Это Вирус Под Вином!?
19 Oct, 24 -
Сколько Стоит Активный Пользователь?
19 Oct, 24