пятница, 23 сентября 2011 г.

[prog.flame] Каким же образом знание разных языков делает программиста лучше?

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

Для того, чтобы продолжать дальше нужно определиться, кто такой “хороший программист” и что означает “быть лучше”. Имхо, начинать нужно с того, что бы определить понятие “хорошая программа”. Хорошая программа – это программа, которая:

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

Соответственно, хороший программист – это такой, который умеет делать хорошие программы. А из чего это умение складывается?

Я бы поставил на первые места следующие составляющие:

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

2. Умением выбирать простые и удобные проектные решения.

3. Умение писать простой и понятный код.

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

4. Умение связно и понятно излагать собственные мысли. Как в устной речи, так и (особенно) в письменном виде. Просто удивительно иногда, насколько тяжело бывает понять написанное умным человеком – вроде бы и правильно все, но чтобы разобраться нужно поломать голову. Из-за банальной причины – пишущий не может поставить себя на место читателя.

5. Умение поддерживать нормальные человеческие отношения с коллегами. Неприятно об этом говорить, но заносчивость, зазнайство, поведение в стиле “я-то знаю, а вы сами должны до всего додуматься”, скрытность (“как я реализую этот модуль – это моя проблема, никого больше это не касается”), некоммуникабельность, обидчивость и пр. встречаются. К счастью, не часто.

Так вот, я не понимаю, каким образом знание нескольких десятков языков способны развить вышеуказанные умения. Хотя бы первые три.

По первому умению. Тут языки программирования вообще не причем. Здравый смысл + опыт. Еще лучше, когда у человека есть врожденная способность разбираться в предмете досконально. А так же умение “примерить чужую шкуру” – поставить себя на место заказчика чтобы уяснить, зачем нужна какая-то фича программы.

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

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

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

По третьему умению. Во-первых, простой и понятный код – это, во многом, следствие опыта, чувства стиля и вкуса. Во-вторых, это следствие хорошего знания языка и, что чрезвычайно важно, знание best и worst practicies для этого языка.

И вот здесь я склонен считать, что знание разных языков программирования вовсе не способствует упрощению кода. А может даже и наоборот. Поскольку на каждом языке нужно писать именно так, как принято писать на этом языке. Можно на Ruby писать как на Java. Но лучше все-таки использовать Ruby way. И в Java не стоит тащить привычки из C++. А чтобы этого не происходило, требуется a) хорошее знание языка (которое приобретается за счет длительного опыта, набивания шишек и их переосмысления) и b) отсутствие жгучего желания воплотить в X вот эту классную фишку из Y. И я, честно говоря, не понимаю, как знание многих языков программирования помогает пунктам a) и b).

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

PS. Кстати говоря, я придерживаюсь мнения, что здесь имеет место путаница. Не изучение языков делает программистов хорошими. Это хорошие программисты зачастую имею желание изучать разные языки. Так что здесь скорее причина и следствие перепутаны ;)

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

Анонимный комментирует...

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

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

> Точно можно утверждать, что человек с опытом в разных языках программирования способен более адекватно выбрать для конкретной задачи наиболее подходящий инструмент. Это да, с этим не поспоришь. Другое дело, что возможностей для такого выбора у очень большого процента программистов просто нет – все уже выбрано за нас.

Вот в этом абзаце Вы ИМХО начали за здравие а кончили за упокой. Т.е. я категорически согласен с первой частью и так же категорически не согласен с тем что у большого процента программистов выбора нет. Один и тот же код который каждый из программистов пишет каждый день можно написать сотней разных способов, и эта сотня разных способов отнюдь не идентична между собой ни по одному параметру. И программист каждый день выбирает один из способов, и увидеть сильные или слабые стороны тех или иных способов - это умение как раз и "прокачивается" через знание разных языков (а ещё лучше - разных парадигм) программирования.

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

@Left:

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

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

Тот же более низкий уровень о котором говорите вы...

Я бы здесь искал причину не в языках, а в других примерах кода, которые приходится разбирать при изучении другого языка. Другие задачи, другие подходы.

Похожего эффекта можно достичь и при анализе чужих разработок на одном и том же языке. Я так думаю.

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

> обладая знаниями в C, C++, Java, Erlang и Haskell можно сделать выбор в пользу того или иного решения исходя из текущих условий.

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

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

Вот смотрю я на boost::phoenix и думаю насколько его легко и быстро сможет освоить программист который пусть хотя бы даже поверхностно не знает функциональные языки :)

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

@Rustam:

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

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

Изучение нового языка дает новую перспективу, взгляд на твой главный язык под другим углом, более четкое понимание решений (или ошибок) создателей языка.
Плюс программист изучает новые подходы и вполне может потом применить их в каком-то виде на своем главном языке (см например мой template pattern matching - казалось бы, какое отношение ПМ имеет к шаблонам, но сам изученный ПМ-подход уже выстраивает мозги в новом направлении и твой арсенал возможных подходов автоматически расширяется).

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

@Евгений Охотников

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

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

Я поддерживаю мнение, что знание разных языков делают программиста лучше.
В посте уместно затронут момент о глубине знания языка, опыт работы с ним, знание приемов -- это достаточно важно.
Говорилось еще о здравом смысле. Прочитав пост, складывается впечатление, что если человек знает разные языки, то он этот смысл теряет (пытается тянуть в один язык из другого ненужные элементы, приемы, итд). Но мы понимаем, что вырожденные случаи рассматривать незачем: таким людям и знание одного языка мешает (пытаются навернуть с его помощью такое, что волосы дыбом).

Тут вообще встают вопросы:
- кому помогает изучение языков;
- когда помогает (сразу лекарство действует, или постепенно, или через продолжительное время), а считается ли поздний эффект помощью?
- в чем именно помогает.
Ответы не такие простые, требуют хороших примеров. Когда будет свободное время (жаль что не скоро), я постараюсь написать пост об этом, и поделиться ссылкой.

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

Так же и с языками, которые кардинально отличаются друг от друга. Они дают возможность посмотреть на разные подходы к вычислениям. С разных сторон взглянуть на алгоритмическую сложность, на варианты композиции кусков программы, на формирование структур данных и способы работы с ними. Человек лучше ощущает trade-off в достижении одного результата разными способами, как средствами одного языка, так и при использовании разных. При использовании разных языков в уме выделяютс абстракции, которыми раньше не мыслил. Например, вместо "толстеньких" блоков с циклами, внутри которых куча "ручных" вычислений, люди начинают использовать итераторы: новая абстракция изменила композицию. А потом люди понимают, что интерфейс итератора дает маловато.

Только считается ли это за помощь? Мне кажется, что под помощью понимают немного разные вещи, в зависимости от желаний. Если человек хочет через пару лет уйти в менеджеры, то ему такая помощь нафиг не нужна, абсолютно. И это логично.

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

Как-то сумбурно получилось.

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

@jazzer:

>(см например мой template pattern matching - казалось бы, какое отношение ПМ имеет к шаблонам, но сам изученный ПМ-подход уже выстраивает мозги в новом направлении и твой арсенал возможных подходов автоматически расширяется).

О каком template pattern matching идет речь?

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

@Easy

Огромное спасибо за развернутый ответ.

>Но мы понимаем, что вырожденные случаи рассматривать незачем: таким людям и знание одного языка мешает (пытаются навернуть с его помощью такое, что волосы дыбом).

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

>Роди мысль, и никто не мешает потом перевести ее на средства, адекватные повседневным рабочим инструментам заказчика.

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

Как бы то ни было, в арсенале программиста должно быть несколько языков -- один основной (вроде C++, C# или Java), второй из класса скриптовых (Ruby, Python, Perl). Если к этому во время обучения было добавлено еще что-нибудь вроде Prolog, Scheme или Mathematica, то у человека уже приличный кругозор для выбора адекватного задаче инструмента.

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

> Ведь не знание другого языка вас толкнуло на создание прототипа.

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

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

Для прототипа -- может и да. Хотя.

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

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

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

@Easy:

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

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

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

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

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

@Easy:

> А цена овладения ими совсем не так велика, как кажется.

Ну вот вопрос цены меня очень интересует. По собственному опыту -- мне потребовалось около года, чтобы почувствовать т.н. Ruby way и начать программировать на Ruby именно на Ruby. При этом в то время на Ruby я писал даже больше, что на C++.

Язык C++ приходится изучать постоянно.

Т.е. я думаю, что хорошая степень владения инструментом обходится не дешево.

NN​ комментирует...

Знание разных языков так же "мешает", знаешь как сделать правильно, а не можешь :)

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

@NN:

Есть такое дело. При этом то, что ты считаешь правльным (исходя из предпочтений к языку X) в языке Y может оказаться вовсе не правильным. Не смотря на твое собственное к этому отношение.

Помнится, Страуструп в "Дизайн и эволюция языка C++" много об этом писал. В частности, о попытках перетаскивания в C++ объектных иерархий с единым корнем наследования.

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

@Евгений Охотников

>> А цена овладения ими совсем не так велика, как кажется.

> я думаю, что хорошая степень владения инструментом обходится не дешево.

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

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

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

@Easy:

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

Точно не один.

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

вот это:

b) отсутствие жгучего желания воплотить в X вот эту классную фишку из Y

означает лишь то, что нынешняя индустрия IT находится в говне

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

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

хотя конечно нормальный ЯП был бы намного лучше

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

чтобы разговор был предметным (хотя это конечно отнюдь не лучший пример):

std::cout << "Hello, $username";

можно транслировать в

std::cout << _add2("Hello,", username);

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

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

@имя:

>хотя конечно нормальный ЯП был бы намного лучше

"Нормальный язык" -- это понятие субъективное. А значит его никогда не будет. Поскольку у разных людей разные взгляды на одни и те же вещи.

Я, например, считаю, что не следует писать такой код, как Boost.Spirit или Boost.Phoenix, не говоря уже про Boost.Lambda. Однако, есть люди, которые придерживаются совершенно противоположного мнения и успешно используют эти вещи.

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

> Я, например, считаю, что не следует писать такой код, как Boost.Spirit или Boost.Phoenix, не говоря уже про Boost.Lambda. Однако, есть люди, которые придерживаются совершенно противоположного мнения и успешно используют эти вещи.

это пример вынужденной субъективности, а не настоящей

пока в с++ нет концептов и хорошего синтаксиса, достаточно мощные шаблонные библиотеки будут торчать "кишками наружу" и использовать кривой/кривоватый синтаксис

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

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

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

@имя:

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

Не, тут дело в другом. Язык всегда рано или поздно начинает использоваться на грани своих возможностей. И, поскольку изменение языка -- дело не быстрое, его возможности будут пытаться расширять каким-то библиотечным образом. Через экстремальное шаблонное программирование в C++, через анотации или AspectJ в Java, через какие-нибудь трехэтажные монады в Хаскеле.

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

>О каком template pattern matching идет речь?
http://www.rsdn.ru/forum/cpp/3722136.1.aspx
Но это как раз тот случай, когда кишки наружу из-за синтаксической невозможности достаточно качественно все упрятать.

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

Кстати, веселая статья в тему:
http://lukeplant.me.uk/blog/posts/why-learning-haskell-python-makes-you-a-worse-programmer/

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

@jazzer:

>http://www.rsdn.ru/forum/cpp/3722136.1.aspx

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

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

@jazzer:

>Кстати, веселая статья в тему

В каждой шутке есть доля шутки. Автор-то подметил важную вещь -- когда приобщаешься к языку, который тебе нравится (в моем случае это был Ruby), а потом возвращаешься на тот, за который платят (C++, Java, C#...), то нужно наступить на горло собственным желаниям. И писать так, как принято на "менее выразительном" языке. А не так, как хотелось бы.

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

> Это как раз код, который я из-за собственного скудоумия предпочитаю не писать вообще.

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

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

> нужно наступить на горло собственным желаниям.

А не надо наступать, надо юзать правильные библиотеки ;)
Тогда код будет выглядеть вот так:

std::cout << join( foo_list | transformed(&Foo::description) | filtered(&std::string::size), "\n" );

Имхо, даже читабельнее, чем хаскел и питон вместе взятые, по крайней мере тот код, который приведен в статье ;)

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

@jazzer:

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

Хотя все можно было бы сделать намного проще.