Почему плохо писать что-то на языке X, как будто вы пишете программу на языке Y с точки зрения использования общей парадигмы кодирования [закрыто]

25

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

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

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

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

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

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

[править] Я хотел бы уточнить, что предложение комара [1] не появилось в поиске, который я проводил до того, как начал задавать свой вопрос. Однако, хотя его предложение действительно охватывает один аспект вопроса, вопрос, с которым он связан, не отвечает сути моего вопроса, а лишь является его частью. Мой вопрос больше об ответе, который я получил на мой стиль кодирования и профессиональные аспекты обработки различных стилей кодирования и (очевидных) уровней мастерства. С моим предыдущим вопросом о SO и его ответом как наглядным примером. [/редактировать]

Тогда возникает вопрос: зачем издеваться над тем, кто не использует ваш стиль кодирования?

Вопросы / подразделения под рукой для меня:

  • Почему было бы плохой практикой программирования использовать более подверженный ошибкам код в ситуациях прототипа, если рефакторинг впоследствии делает его более устойчивым?
  • Как может программа, написанная на C ++, быть похожей на Java? Что делает его плохой программой (учитывая, что я указал намерения текущего стиля и запланированную работу по улучшению?)
  • Как бы я был плохим профессионалом, если бы решил использовать конструкцию, которая используется в определенной парадигме программирования (например, ООП / ДП)?

[1] Быстро и с ошибками разрабатывать, затем исправлять ошибки или медленно, осторожно относиться к каждой строке кода?

О нет
источник
5
Возможно, вам лучше задать этот вопрос ребятам из C ++ Lounge. Сначала наденьте свой огнестойкий костюм.
Роберт Харви
48
Люди C ++ - необычная порода среди программистов. Ваш инструментарий Java - разумный, хорошо понятный набор инструментов со знакомыми инструментами в мягкой кожаной сумке, который будет работать в любом магазине инструментов. C ++ - это целый инструментарий, в котором есть рип-пила, механическая дрель и некоторые инструменты, которые никто не может распознать, с которыми толпа C ++ может обращаться как ниндзя. Это огорчает их, когда кто-то входит и кладет какой-то инструмент обратно на полку в неправильном месте. Они - «мера дважды, один раз» программистов.
Роберт Харви
13
Возможно, это та же реакция, что и у вас, с кодом Java, который был написан как FORTRAN: весь код в одном классе, никаких коллекций, только массивы фиксированного размера, с отдельными intпеременными для отслеживания фактической длины.
Кевин Клайн
14
Если вы пишете на C ++, как Java, вы, вероятно, получите слишком много выделений кучи, что сделает вашу программу хуже, чем могла бы. Языки, как правило, разрабатываются и оптимизируются для продвижения определенных шаблонов, и если вы нарушите их, для вас все будет хуже.
Gort the Robot
5
Вы отправили код онлайн, чтобы получить некоторую форму помощи. Я понимаю, что вы не хотели / не ожидали всех отзывов о вашем стиле, но вы бы предпочли никакой помощи вообще? Ты берешь хорошее с плохим. Программисты должны искать ошибки в коде; это то, что мы делаем.
JeffO

Ответы:

26

Не видя рассматриваемого кода, есть несколько способов написания Java-кода на C ++, некоторые хуже, чем другие.

  1. С одной стороны, вы можете расположить ваш исходный код как Java: все в одном файле, все в пределах определения класса и т.д .:
    class HelloWorldApp {
    public:
        void main() {
            cout << "Hello World!" << endl;
        }
    };
    Вот как будет выглядеть исходный код Java. Это технически допустимо в C ++, но помещать все в заголовочный файл и все встраиваемые (определяя его в объявлении класса) - ужасный стиль и убьет вашу производительность компиляции. Не делай этого.
  2. Чрезмерно OO - Для упрощения, в Java это Царство Существительных , где все является объектом. Хороший (т.е. идиоматический) код C ++ с большей вероятностью использует свободные функции, шаблоны и т. Д. Вместо того, чтобы пытаться втиснуть все в объект.
  3. Нет RAII - вы уже упоминали об этом - используя указатели и ручную очистку вместо умных указателей. C ++ предоставляет вам такие инструменты, как RAII и умные указатели, поэтому хороший (т.е. идиоматический) код C ++ использует эти инструменты.
  4. Нет продвинутого C ++. Основы Java и C ++ достаточно похожи, но как только вы попадаете в более продвинутые функции (шаблоны, библиотека алгоритмов C ++ и т. Д.), Они начинают расходиться.

За исключением # 1, ни один из них не делает программу на C ++ плохой программой, но это также не тот код, над которым я предпочитаю работать как программист на C ++. (Мне также не понравилось бы работать с не-идиоматическим языком или Perl в стиле C, не-идиоматическим Python и т. Д.) У языка есть свои собственные инструменты, идиомы и философия, и хороший код использует эти инструменты и идиомы вместо того, чтобы пытаться использовать наименьший общий знаменатель или пытается воспроизвести подход другого языка. Написание неидиоматического кода на определенном языке / проблемной области / что угодно, не делает кого-то плохим программистом, это просто означает, что у них есть больше, чтобы узнать об этом языке / проблемной области / что угодно. И в этом нет ничего плохого; есть очень длинный список вещей, о которых мне нужно узнать больше, и, в частности, в C ++ есть масса вещей, которые нужно изучить.

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

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

Если в качестве примера использовать необработанные указатели против интеллектуальных указателей, если вы собираетесь работать в C ++, использование RAII и интеллектуальных указателей является достаточно фундаментальным, чтобы писать код таким образом быстрее , чем возвращаться и очищать его позже. Опять же, неспособность сделать это не означает, что кто-то плохой программист, непрофессионал и т. Д., Но это означает, что есть чему поучиться.

Джош Келли
источник
11
есть идиоматический perl?
фрик с трещоткой
21
@ Onnno Когда ты спрашиваешь "Как я могу вбить этот винт в стену, чтобы он не прогнулся?" все скажут вам не использовать молоток.
Сьорд
9
@ Onnno В C ++ указатели и newсчитаются powertools. Автоматическое хранение это ручной инструмент.
Сьорд
9
@ Onnno: Вы должны понимать, что курсы программирования на C ++, как правило, отстают в освоении современных идиом, и то, что считается хорошим C ++, также сильно эволюционировало с момента изобретения C ++.
Барт ван Инген Шенау
7
Из-за истории C ++ и огромного числа программистов, которые изучали язык до появления многих более продвинутых функций языка, существует множество дерьмовых C ++, которые все еще пишут люди, которые пишут так же, как и десять лет назад. Хитрость в таких вещах, как RAII, заключается в том, чтобы заставить всех использовать современные методы, чтобы мы могли перестать видеть одни и те же предсказуемые ошибки.
Gort the Robot
42

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

  • Я буду кричать, если вы пишете for ($i = 0; $i < 42; $i++) { … }на Perl, но не на PHP
    (в Perl переменные должны быть объявлены, и такие циклы должны повторяться в диапазоне)
  • Я заплачу, если вы напишите new Foo()на C ++ без уважительной причины, но не на Java
    (C ++ не имеет сборки мусора, поэтому следует использовать RAII. В противном случае Noobs будет пропускать память)
  • Я буду раздражен, если вы объявите все свои переменные в начале вашей функции, кроме C89, Pascal или JavaScript.
  • Я буду использовать facepalm, если вы поместите все свои функции в класс на Python, но не на Java
    (Python - это мультипарадигмальный язык вместо форсированного «OOP» и поддерживает функции на верхнем уровне)
  • Я заплачу, если вы return nullв Scala, но не на любом C-подобном языке
    (потому что у Scala есть Optionтип)
  • Я буду жаловаться, если вы напишите рекурсивный алгоритм в Java, но не в OCaml
    (потому что стек Java быстро переполняется, тогда как в OCaml есть оптимизация хвостового вызова)
  • ...

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

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

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

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

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

Амон
источник
Вы совершенно правы в отношении некоторых своих замечаний, но, в конце концов, я не думаю, что вы попали в цель. Вы предполагаете достижение знания до того, как получите опыт, который приобретет знание.
Onno
4
@ Onnno Мои основные моменты (которые отвечают на вопросы, которые вы задавали), это то, что вы не можете перенести привычки с одного языка и предположить, что это лучший метод на другом языке, и что попытка написать чистый код с самого начала предпочтительнее, чем очистка это позже. Очистка кода - в меру своих возможностей - обязательна, прежде чем просить других о помощи (см. Sscce.org для получения советов по хорошим фрагментам кода). Сброс мусорного кода на SO с «пожалуйста, исправьте это» недопустим, особенно если вы знаете лучше.
Амон
2
Но в отношении вопроса, на который вы намекаете: ответ jm666 содержит ключевой момент: гуру думает: «зачем вам спрашивать о Х, если вы сами не хотите стать Х-гуру?» Я слишком часто нахожусь в этом бесполезном мышлении. , Возможный способ избавиться от этого - упомянуть, что вы все еще находитесь в самом начале кривой обучения и изучите это позже, но сейчас у вас есть этот более неотложный вопрос. Однако это проблема коммуникации, а не проблема программирования.
Амон
6
И C ++, и C # имеют optional<T>и Nullable<T>соответственно. Кроме того, практически все утечки памяти в C ++ без RAII, нуб или нет.
DeadMG
Я считаю, что объявление переменных в начале блока обычно облегчает чтение кода на большинстве языков. Таким образом, вы точно знаете, где искать, когда вам нужна помощь, помня, какие типы всех ваших переменных и что такое.
Смак
12

Я не хардкорный разработчик C ++, но ...

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

Следует иметь в виду, что ошибка в C ++ обычно означает «неопределенное поведение». На безопасном языке самое худшее, что может случиться, - это исключение, немедленно прекращающее вашу программу. В C ++ вам повезло, если вы получили segfault. Вполне возможно, что ваша программа продолжает делать что-то не так. Он также может вести себя корректно в течение определенного периода времени и обнаруживать ошибки намного позже, или он может вести себя правильно все время, но в конечном итоге съедает всю вашу память.

В любом случае достаточно одной ошибки, чтобы полностью вывести выполнение программы с рельсов на неизведанную территорию. Вполне вероятно, что для разработчика на C ++, работающего полный рабочий день, «базовый случай» означает «нет возможности неопределенного поведения или утечек памяти».

Как может программа, написанная на C ++, быть похожей на Java? Что делает его плохой программой?

Я не думаю, что есть ответ на этот вопрос, который не будет в значительной степени спекулятивным и самоуверенным. Однако, если вы хотите, чтобы я это понял, Java имеет тенденцию связывать пару антипаттернов, таких как тот факт, что все должно быть объектом. Где на других языках вы бы передать указатель, функтор, или функцию, в Java вы обычно найти тонны бессодержательных и узко-полезные ThingDoers, FooFactoriesи IFrobnicatorsкоторые являются просто функциями в маскировке.

Точно так же, когда в других языках вы можете передать простой кортеж или безымянную структуру, в Java для объединения даже двух объектов в простой контейнер данных требуется предварительно определить 30-строчный класс NamedThing с сеттерами, геттерами и Javadocs. Относительное отсутствие функций в Java заставляет программистов делать объектно-ориентированные двойные сальто, чтобы иногда что-то делать. Полученный код редко бывает идиоматическим за пределами Java.

Тогда есть тот факт, что в C ++ вам нужен очень упрощенный граф объектов для управления памятью вручную; обычно объект принадлежит ровно одному другому объекту. В Java вам не нужно следовать таким строгим ограничениям, потому что сборщик мусора гарантирует, что все будет очищено, когда на них больше не будет ссылок. Таким образом, существует определенный риск неправильного управления памятью, если вы просто транслитерируете код с Java на C ++.

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

Doval
источник
1
Большая часть этого облегчена с Java 8 - Lambdas едет, чтобы в основном сохранить день :-)
Martijn Verburg
@MartijnVerburg Согласен, огромный шаг вперед. Но технологические проблемы легко решить! Старые привычки умирают крепко, а клейма еще сильнее. Черт, некоторые люди пойдут так далеко, что будут жаловаться, что Java не нуждается ни в одной из этих «новых» функций, и что он на пути к тому, чтобы стать следующим C ++.
Доваль
Да, я всегда покачал головой - Java намеренно всегда будет развиваться медленнее, чем другие языки, поскольку это долгосрочная рабочая лошадка. JVM, однако, может прыгать вперед на дрожжах несколько быстрее, что позволяет таким вещам, как Lambdas, в конечном итоге прийти к языку.
Мартейн Вербург
6

Слегка не по теме ответ ...

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

Я в мире Perl - когда увидим что-то вроде:

$imax=$#array;
$str=""
for($i=0; $i<$imax; $i++) {
    $str = "$str" . $array[$i];
}

вместо того:

my $str = join '', @array;

Обязательно прокомментирую это - (читай: научи автора) о joinфункции.

В любом случае, слишком много критики контрпродуктивно, и один из лучших примеров следующий: (взято с: http://perl-begin.org/humour/#How_can_I_switch_off_the_T.V..3F )

(Этот бит был анонимно опубликован пастботу 23 марта 2011 года. Он помещен здесь для потомков после некоторого редактирования.) - тоже немного отредактирован

Вопрос: как я могу включить телевизор?

Что ОП хочет услышать?

Например: найдите кнопку включения / выключения пульта ДУ телевизора и нажмите ее. Кнопка обычно красная и расположена в самой верхней строке пульта.

Ответ эксперта #perl: Во-первых, что вы имеете в виду под «включением»? Определите это первым. Nopaste ваш телевизор, пульт дистанционного управления и гостиная тоже.

... после nopaste:

Ваша комната безобразна И телевизор выглядит ужасно. Используйте Mr. Clean на экране и сначала очистите гостиную. Используйте три чистящих швабры вместо двух. Используйте HDMI и никогда не используйте разъемы Scart (?), Если вы действительно этого не хотите. На пульте телевизора есть нечитаемые кнопки, сначала очистите. Вы новичок, так что читайте:

http://experts.blog/how_to_design_a_future_3D_TV.html http://experts.blog/the_basics_of_tv_repairing.html http://experts.blog/viruses_in_living_room_short_essay.html http://experts.blog/global_tiphreh

Гость IRC: Но я не хочу быть телевизионным экспертом.

Ответ: Почему вы хотите включить телевизор?

jm666
источник
1
Этот ответ не по теме. Это точно объясняет, почему кто-то будет критиковать нетрадиционное использование языка, и почему иногда эта автоматическая критика может зайти слишком далеко. Мне это нравится.
Трихоплакс
1

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

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

Как может программа, написанная на C ++, быть похожей на Java? Что делает его плохой программой (учитывая, что я указал намерения текущего стиля и запланированную работу по улучшению?)

В Java вам не нужно думать о том, кто владеет определенным объектом, вы просто передаете ссылку и забываете о ней, как будто это ничто. Однако в C ++ должно быть четкое определение того, кому принадлежит объект и кто отвечает за его очистку.

Как бы я был плохим профессионалом, если бы я решил использовать конструкцию, которая используется в определенной парадигме программирования (например, ООП / ДП)

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

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

чокнутый урод
источник
Я вижу, что забывание об улучшении может быть проблемой для некоторых, но я держу длинный список задач, и я очень дисциплинирован в добавлении тегов todo для таких видов работ. (именно поэтому мне нравится VS, он хорошо справляется с управлением работой) То же самое относится и к документации. Я не пишу строку кода, пока не написал для нее документацию. Что касается вопроса о собственности, то из-за диаграмм последовательности я думаю, что у меня есть хорошее представление о том, кто с кем связан.
Onno
1
@Onno: Честно говоря, никто не знает и не заботится о том, насколько хорошо вы лично отслеживаете эти вещи. Подавляющее большинство людей, которые пишут C ++, который выглядит как Java или C, даже не настолько дотошны. Для них гораздо лучше научиться делать вещи правильно с первого раза, чем написать самим себе записку, чтобы вернуться и исправить это позже, потому что опыт показывает, что они практически никогда этого не делают.
chao