понедельник, 22 апреля 2024 г.

[prog.c++] Вредных советов пост: пара-тройка способов усложнить жизнь тем, кто будет сопровождать код после вас

Хочу поделиться многолетним опытом. Работает на 100%, а иногда и на все 146%. Так смело можете брать на вооружение, если решили конкретно поднасрать своим коллегам.

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

Поверьте, настоящие программисты (тм) всегда будут точно знать, что означают it->first или std::get<3>(*it).

Наверняка на вашем пути встретятся душнилы, которые будут утверждать, что std::pair и std::tuple нужно ограничивать очень маленьким скоупом. Вроде возвращаемого значения лямбда-функции или же обычной вспомогательной функции, но которая вызывается всего в одном-двух местах. А для всего остального нужно создавать нормальные структуры с названиями полей, соответствующими предметной области.

Не обращайте на них внимания. Это же склеротики, которые не могут удержать в памяти даже два простых названия -- first и second, хотя что может быть проще? Ну и наверняка им платят за строчки кода, а не за решение проблем. Вот они и фигачат по 100500 строк там, где можно обойтись одним std::pair-ом.

Во-вторых, забудьте такую вещь, как strong typedef. Тем более, что в C++ из коробки ее и нет. Так что это вообще не ваш путь, а те, кто про пытается заикаться о strong typedef, просто учились программировать на Pascal-е, а значит старпёры и ничего не понимают в современной разработке софта.

Если у нас есть строковое имя пользователя и строковый же пароль в виде открытого текста, то достаточно простого std::string.

Вводить какие-то новые типы UserName и PlainTextPassword? Ради чего? Ради того, чтобы случайно не пихнуть пароль туда, где ожидается имя пользователя?

Да это вообще смешно. Ведь так никто не делает. А если вдруг, так это от кривизны рук. Настоящие программисты (тм) таких ошибок не допускают.

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

Так что никаких strong typedef-ов. Забудьте как страшный сон.

Ну и в качестве бонуса: вам не нужны ни using, ни typedef. Если у вас есть map, значением которого будет vector из queue, то вот прямо так и нужно записывать. Никаких вспомогательных using-ов и typedef-ов!

Ну а самые прозорливые читатели могли догадаться, что все эти советы легко комбинируются. Ведь это так просто:

void process_appropriate_items(
      const std::vector<
            std::pair<
                  std::pair<intint>,
                  std::tuple<std::string, std::string, std::string, std::string> > > & what)
{
   for(const auto & p : what)
      if(p.first.second > 0)
         process(std::get<3>(p.second));
}

Зачем выдумывать что-то еще? Неужели вам не понятно что означает p.first.second и std::get<3>(p.second)? Да ну, не может такого быть!


Перестрахуюсь на всякий случай: в каждой фразе здесь должен быть тег "сарказм". Иногда и не один.

3 комментария:

sv комментирует...

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

eao197 комментирует...

@sv

Эт да, не поспоришь.

Но я пишу о том, что вижу постоянно.
А вот union, к счастью, видеть приходится очень и очень редко.

sv комментирует...

Значит, это мне так повезло...