Написание надежного кода против чрезмерного проектирования

33

Откуда вы, ребята, знаете, что вы пишете самый надежный код из возможных без чрезмерного повышения квалификации?

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

Фран Севильано
источник
2
Кодируй это в Agda2
SK-logic
конкретный пример очень поможет сделать вашу точку зрения. :)
Жоао Портела
Могу ли я просто проверить, что вы действительно спрашиваете об устойчивости, то есть о «способности системы продолжать работать при наличии недопустимых входных данных или стрессовых условий окружающей среды», потому что некоторые ответы, кажется, думают, что вы говорите о расширяемости.
DJClayworth
Я работаю в сумасшедшие сроки, плюс для демонстрации, поэтому я могу с радостью быстро избавиться от паралича совершенства.
Работа
1
Вот статья , которая говорит о теме: code-tag.com/2017/04/02/...
Сан -

Ответы:

39

Откуда вы, ребята, знаете, что вы пишете самый надежный код из возможных без чрезмерного повышения квалификации?

Что вы считаете надежным кодом? Код, который уже на будущее и настолько мощный, что может справиться с любой ситуацией? Неправильно, никто не может предсказать будущее! И опять не так, потому что это будет сложный, неразрешимый беспорядок.

Я следую различным принципам: прежде всего YAGNI (пока) и KISS , поэтому я не пишу ненужный код. Это также эффективно предотвращает чрезмерную инженерию. Я выполняю рефакторинг приложения, когда требуются расширения. Современные инструменты рефакторинга позволяют довольно легко создавать интерфейсы и впоследствии обмениваться реализациями, когда они вам нужны.

Затем я пытаюсь сделать код, который я пишу, максимально надежным, что включает в себя устранение как можно большего количества путей, которые может пройти программа (и состояний), и немного спартанского программирования . Большую помощь представляют «атомарные» функции / методы, которые не полагаются на внешние состояния или, по крайней мере, не оставляют программу в несостоятельном состоянии при сбое. Если вы сделаете это хорошо, очень маловероятно, что вы когда-нибудь получите спагетти-код, и это тоже благо для удобства обслуживания. Кроме того, в объектно-ориентированном проектировании принципы SOLID являются отличным руководством по созданию надежного кода.

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

Надежный код - это всегда простой и чистый код, но простота - это черта, которую не всегда легко достичь. Тем не менее, вы должны стремиться к этому. Всегда просто пишите самый простой код и усложняйте его только тогда, когда у вас нет другого выбора.

Простота крепка, сложность хрупка.

Сложность убивает.

сокол
источник
2
Потому что у него нет тонны классов, фабрик и абстракций. Это парадокс, но некоторым людям это нравится. Понятия не имею почему.
Кодер
5
Это Спарта!!!
Том Сквайрс
4
Люди, которые не занимались этим двадцать лет, просто не понимают, как сложность может вас убить. Они думают, что они такие умные. Они тупые, не умные. Эта сложность убьет тебя мертвым.
PeterAllenWebb
1
Надежность - это не гарантия будущего, а продолжение работы с недопустимыми входами или стрессовой средой - Code Complete p464.
DJClayworth
5
Если спрашивающий не использует «здравый» в другом смысле, чем тот, который я понимаю, вы отвечаете на другой вопрос. Он не спрашивает «должен ли я кодировать, чтобы учесть будущие требования», он спрашивает «какие необычные случаи ввода мне следует обрабатывать». Ни один из YAGNI, KISS и SOLID не имеет отношения к делу. Вам нужно разрешить миллион пользователей, пытающихся войти одновременно? Что произойдет, если имя пользователя начинается с обратной косой черты? Ни на один из этих вопросов ЯГНИ не ответил.
DJClayworth
8

Я стараюсь сохранять равновесие, ориентируясь на

  • обработка всех возможных путей выполнения в существующих вариантах использования (это часть «робастности»),
  • Включая функции / требования, я уверен, что это произойдет в обозримом будущем, и
  • Вещи, которые я знаю по своему опыту, которые понадобятся для долгосрочного сопровождения базы кода (т. е. поддержания чистоты кода и возможности его тестирования).

Это нечеткая граница - иногда мне удается выполнить какую-то ненужную работу, иногда я не могу сделать что-то, что позже становится необходимым. Если промахи не большие, я в порядке. Во всяком случае, я стараюсь учиться на своих ошибках.

Петер Тёрёк
источник
Пример был бы великолепным здесь, обрабатывая все возможные пути выполнения в существующих
сценариях
5

Разница между надежным и сверхинжинирингом - это разница между изящной обработкой всех возможных вариантов использования, даже странных и незначительных вариантов использования, которые НЕ ДОЛЖНЫ происходить. Когда я говорю «изящно», я имею в виду, что пользователь входит в причудливый случай исключения или сталкивается с ситуацией, которая требует неподдерживаемой или неопределенной функции, которая не была определена, и код корректно завершается без сбоев или информирует пользователя о неподдерживаемой функциональности.

С другой стороны, перепроектирование может попасть в сферу полной реализации функций, которые не были нужны или запрошены (некоторые функции, которые клиенту НЕ НУЖЕН, но никогда не запрашивали!) ИЛИ это можно определить, получив слишком сложный дизайн или слишком сложный код для решения относительно простой проблемы.

maple_shaft
источник
4

1) Получить требования.

2) Написать минимальный код для удовлетворения требований. Если что-то неоднозначно, сделайте обоснованное предположение. Если это супер неоднозначно, вернитесь к 1.

3) Отправьте на тестирование.

4) Если тестеры говорят, что это хорошо, задокументируйте утверждение. Если что-то не так, вернитесь к 1.

Сосредоточьтесь на прохождении тестов, а не на прогнозировании тестов. Если у вас нет тестеров ... получите тестеры! Они важны не только для проверки правильности кода, но и для всего процесса разработки.

Морган Херлокер
источник
1
+1 за фокусировку на прохождении тестов, а не на прогнозировании тестов, однако многие разработчики, как и я, должны делать и то, и другое в отсутствие сильных бизнес-аналитиков.
maple_shaft
@maple_shaft - очень верно. Дело в том, что эти проблемы возникают из-за чужой некомпетентности. Подчеркивание чужой работы - это путь к выгоранию. Если бы моя компания была достаточно глупой, чтобы заставить меня сделать дебиторскую задолженность за месяц, я не был бы слишком разочарован в себе, если бы это не получилось хорошо. Определение требований обычно подразумевает описание того, что вы делаете каждый день, чтобы его можно было автоматизировать. Если никто из сотрудников не может сделать это, ну ... компания может быть в беде.
Морган Херлокер
3

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

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

Существует сильная тенденция пытаться жестко управлять избыточностью посредством уведомлений. Это не только трудно убедиться, что они правильные, но и может привести к огромной неэффективности. (Часть соблазна писать уведомления возникает потому, что в ООП они практически поощряются.)

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

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

Майк Данлавей
источник
3
  • написать для повторного использования.
  • написать тесты. тривиальные, нетривиальные, некоторые нелепо сложные, чтобы увидеть, как он справляется в таких условиях. Тесты также помогут вам определить форму интерфейса.
  • написать программу, чтобы потерпеть неудачу сильно (например, утверждение). мой код имеет массу повторного использования, и я тестирую для тонны случаев - есть больше проверки / обработки ошибок, чем фактическая реализация (на основе количества строк).
  • повторное использование.
  • немедленно исправить вещи, которые идут не так, как надо.
  • учиться и строить из опыта.

ошибки будут появляться по пути, но они (к счастью) будут локализованы, и они (в большинстве случаев) будут обнаруживаться очень рано в тестировании. Другое преимущество повторного использования состоит в том, что клиент / вызывающая сторона может сохранить большую часть проверки / скаффолдинга ошибок, используя то, что приносит имплементация.

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

джастин
источник
2

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

thiton
источник
2

Надежность: степень, в которой система продолжает функционировать при наличии недопустимых входных данных или стрессовых условий окружающей среды. (Код завершен 2, p464)

Важным вопросом здесь является вопрос, насколько важна для вас надежность. Если вы являетесь пользователем Facebook, очень важно, чтобы ваш веб-сайт продолжал функционировать, когда кто-то вводит специальные символы на входе, и чтобы ваш сервер работал, когда в систему одновременно вошли 100 миллионов пользователей. Если вы пишете сценарий для выполнения обычной операции, которую выполняют только вы, вам все равно. Между ними много уровней. Решение о том, насколько вам нужна надежность, является одним из важных навыков, которые должен освоить разработчик.

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

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

  • Как часто эта ошибка может возникать?
  • Сколько стоит эта ошибка?
  • Это для внутреннего или внешнего использования?

Не забывайте, что люди могут и будут пытаться использовать вашу программу неожиданным образом. Лучше, если произойдет что-то предсказуемое.

В качестве последней линии защиты используйте assert или shutdown. Если что-то случится, и вы не сможете решить, как с этим бороться, закройте программу. Это обычно лучше, чем позволить программе продолжаться и делать что-то непредсказуемое.

DJClayworth
источник