четверг, 22 января 2009 г.

I'm not standard. Is C++ the best language?

Продолжение "I'm not standard". Тов.Чистяков, утверждает, что я считаю C++ отличным языком программирования?

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

В качестве замены C++ в разное время я рассматривал Scala, D, Eiffel, Nice (с этим языками я познакомился довольно плотно), а так же OCaml и C# (менее плотно, в особенности C#). Но, в моих текущих условиях, отказаться от C++ просто так все равно не получится. Слишком много кода, который гораздо дешевле развивать и совершенствовать, чем переписывать. Да и выбрать в качестве замены можно разве что Java, из-за ее переносимости. Но, на мой взгляд, безопасность Java является ее единственным достоинством (как языка), по сравнению с C++. Мне доводилось программировать на Java, я был не в восторге. Так что, в какой-то степени, замена C++ на Java -- это смена шила на мыло.

Наилучшие впечатления в качестве языка для разработки промышленного программного обеспечения на меня произвел Eiffel. Особенно в купе с доработками, которые появились в языке после версии 6.1. Но у Eiffel есть две большие проблемы: религия Eiffel и слишком высокие цены на средства разработки. Так что, если только Eiffel внезапно не выпустит бесплатный компилятор с большой бесплатной базовой библиотекой, шансов у него нет.

Еще хотелось бы плотно познакомиться с Ada (особенно в версии стандарта Ada-2005), но до этого пока не дошли руки.

Наилучшие перспективы на будущее, как мне кажется, у двух языков для платформы .Net: C# и F#. Но есть ли хорошие перспективы у самого .Net как у кросс-платформенного проекта? Может быть, со временем Mono покажет. (Я бы сам с удовольствием бы занялся разработкой ПО под какую-то одну платформу, под тот же .Net... Но пока нужно принимать во внимание разнообразные *nix-ы.)

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

I'm not standard. IDE?

Продолжение "I'm not standard". Тов.Чистяков, утверждает, что я не понимаю, зачем нужны навороченные IDE с интеллисенсом, рефакторингом и т.д.?

Не то, чтобы я не понимал, зачем нужны IDE вообще. Думаю, что я понимаю, зачем все эти комбайны со всеми примочками нужны людям. И я сам впечатлен тем, что могут выделывать современные IDE уровня IntelliJ IDEA.

Однако, вопрос не в том, зачем нужны IDE людям. Я бы даже сказал, среднестатическим разработчикам, на которых IDE, собственно, и рассчитаны. Вопрос в том, зачем эти IDE мне? Пойдем по порядку.

Интеллисенс. Он же автокомплит или, по-русски, автодополнение. Вещь хорошая, очень нужная. Но тут получается так: если я пишу программу прямо на компьютере и редактор начинает мне подсказывать название методов и порядок параметров, то я начинаю притормаживать. В прямом смысле этого слова. Т.е. я начинаю набирать имя метода, редактор мне его пишет полностью и даже ставит открывающую скобку. И тут я замираю в ожидании, когда редактор продолжит мой код. Ну а как же? Он же знает, какой метод я хотел вызвать, так неужели он не знает, что я хотел этому методу передать? А оказывается, что не знает. И вот такие вот переключения моего внимания с того, что мне подсказывает IDE на то, что я должен написать сам меня очень сильно выбивают из колеи. Поэтому, когда я пытался пользоваться IDE с такими возможностями (для Java это был, кажется, CodeGuide, для C++ -- Visual Studio, для Eiffel -- EiffelStudio) я вообще отключал интеллисенс. Ну а если я набираю программу с бумаги, то интеллисенс мне и вовсе не нужен, т.к. я уже знаю, что я вызываю и какие параметры передаю при вызове. Что очень помогает в наборе текста, так это автодополнение. Но автодополнение есть не только в IDE, но и в нормальных текстовых редакторах для программистов. Скажем, в gVim-е, коим я пользуюсь уже пятый год.

Рефакторинг. Он мне практически не нужен. Т.к. при программировании на бумаге уже происходит серьезный рефакторинг -- как на этапе записи кода на бумаге, так и при вводе его в компьютер. Поэтому, я практически не нуждаюсь в таких рефакторингах, как выделение фрагмента в отдельный метод или добавление в метод еще одного параметра. Другие типы рефакторингов, такие как переименование атрибутов/методов/классов/пространств имен, изменение иерархии классов и пр. требуются гораздо, гораздо реже. И здесь очень сильно помогают возможности нормальных текстовых редакторов для программистов. В том же gVim-е есть и grep, и мощные функции поиска/замены (в том числе и по регулярным выражениям), и функции записи/воспроизведения действий пользователей. Т.е., хорошо продуманный код и мощный текстовый редактор очень сильно компенсируют отсутствие в моем распоряжении тех средств рефакторинга, которые предлагают современные IDE.

Навигация по коду. Боюсь, что это достоинство современных IDE я не смогу в должной мере оценить. Поскольку так уж получилось, что я работал в небольших командах, в которых каждый занимался своей частью работы. Поэтому каждый хорошо знал собственный код и не нуждался в изучении чужого. Временами, при знакомстве с новой библиотекой или при разбирательствах с уже используемыми библиотеками, приходится копаться в чужом коде. Но, как ни странно, контекстный поиск (будь то grep или встроенный в FAR и Midnight Commander поиск) оказывается вполне достаточным.

Есть еще несколько факторов, которые снижают ценность IDE лично для меня.

Основными языками, которые на данный момент я использую в работе, являются C++ и Ruby. А особенностью данных языков является то, что для них создать настолько же продвинутые IDE, как для Java/C#, не реально. В C++ этому мешают шаблоны, внутри которых невозможно реализовать подсказки, автодополнение и, местами, рефакторинг. В Ruby -- динамическая типизация. Таким образом, для моих рабочих языков все равно нет достаточно продвинутых IDE.

Мне доводилось программировать на C++ под разные платформы. Если попробовать вспомнить в хронологическом порядке, то получится ряд из MS-DOS, Windows разных мастей, OS/2, Linux, OS-9000, Solaris, FreeBSD, NonStop Kernel. С помощью разных C++ компиляторов (Borland, Visual, Watcom, IBM, GCC, Compaq/HP). Подобный зоопарк приводит к нескольким последствиям.

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

Во-вторых, каждая из IDE использует собственный формат проектных файлов. Поэтому, если нужно вести один и тот же проект в разных IDE, то приходится заниматься синхронизацией содержимого этих проектных файлов. Либо, вместо этого, использовать независимые от IDE системы сборки проектов. Вроде make. В результате, я пришел к использованию собственной build-системы (сейчас есть большой выбор подобных средств: SCons, Boost.Jam, CMake, MPC и т.д.), которая использует один и тот же проектный файл на всех платформах для всех компиляторов.

Получается, что на любой платформе я имею один и тот же привычный мне набор инструментов (очень мощный редактор Vim и адаптированную под мои нужды build-систему Mxx_ru). На мой взгляд, подобная мобильность так же компенсирует отсутствие в моем распоряжении IDE класса IntelliJ IDEA.

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

I'm not standard. Programming on paper

Продолжение "I'm not standard". Тов.Чистяков, утверждает, что я читаю большие проекты с бумаги.

Я не читаю большие проекты с бумаги. Я пишу свои проекты с помощью программирования на бумаге. Проекты, как мне представляется, большие для одного человека. Например, ядро последней версии SObjectizer -- это более 40 тысяч строк C++ кода. Еще один проект, написанный мной в одиночку, ObjESSty, это еще 50 тысяч строк. Написанный на Ruby Mxx_ru -- 10 тысяч строк. И есть еще во много раз больше написанного мной закрытого кода. Во всех моих проектах время от времени возникают ошибки, и я не могу сказать, что пишу очень качественный код. Но лучшей характеристикой качества моей работы я считаю фразу, сказанную начальником нашей службы техподдержки (занимающейся эксплуатацией написанных мной систем): "Только твой код я не боюсь запускать сразу на боевых серверах". Для меня это является доказательством того, что каким бы странным или диким не казался кому-то мой подход к написанию кода, этот подход в моем случае дает хорошие результаты.

Почему я использую бумагу? Так сложилось исторически. В 1989-1990 годах, в последнем классе школы у нас была одна пара в неделю по предмету "Информатика". Дисплейный класс из десятка БК-1001 один на пять школ нашего района. Первая часть пары - теоретическая, и только вторая - непосредственно за компьютером. И хоть тогда я написал всего две или три какие-то программы, их исходный текст был подготовлен заранее в тетрадке, а на уроке просто введен и отлажен. Потом были первые курсы университета. С обычным для того времени дефицитом всего, в том числе и машинного времени. У нас, если мне память не изменяет, было что-то около трех пар в дисплейном зале на две недели. Да и в принципе, на первых трех-четырех курсах машинное время для себя приходилось вырывать, иногда с боем, иногда хитростью. Хотя и потом, уже на работе в КБСП, году эдак в 1996-м, когда в наш отдел пришел новенький Pentium-166MMX с 32Mb памяти, было составлено расписание для того, чтобы выделять каждому сотруднику несколько часов в неделю для работы на этом супербыстром монстре...

Ну да вернемся к 1990-му году. Машинного времени было настолько мало, что придя на него неподготовленным, можно было успеть сделать только заданные лабораторные работы. А ведь хотелось большего! Тогда я последовал совету своего преподавателя, Александра Васильевича Лубочкина, о том, что программу сначала нужно писать на бумаге. И это сработало!

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

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

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

Когда программа начинает создаваться на бумаге, можно начинать с чего угодно. Половина функции может состоять из вопросов, а вторая половина быть набором рисунков, например, иллюстрирующих расщепление узлов B+ дерева. Но затем все это начнет структурироваться, начнут вырисовываться группы основных и вспомогательных функций/методов/классов, начнут формироваться зависимости по данным. И все это будет перед глазами, на 5-10 листах формата A4, которые можно разложить на столе и обозревать результаты собственного творчества с высоты "птичьего полета". В результате все обязательно сложится в законченную картину, станет видно, какой параметр куда нужно будет передать и зачем, какие куски кода повторяются слишком часто и как это дублирование можно устранить. Но и это еще не все.
 
Когда программа написана сначала на бумаге, она может очень неформальные комментарии. Ими могут быть схемы/рисунки на полях, какие-то небрежно сделанные заметки или пояснения. Или же большие фрагменты кода могут не содержать комментариев вовсе. Зато при вводе текста в редакторе появляется возможность писать толковые комментарии, описывающие что, для чего и как. Ведь все это уже известно, остается только сформулировать и записать. Поэтому при вводе кода с бумаги не возникает сложностей с тем, чтобы написать перед новым классом развернутый Doxygen-комментарий с полным описанием назначения класса, особенностей его работы и, даже, примерами его использования. Что самым благоприятным образом сказывается на качестве генерируемой по исходным текстам документации.

Но и это еще не все :). Еще несколько положительных свойств программирования на бумаге будут затронуты при обсуждении других вопросов.

I'm not standard. Intro

Один из отцов-основателей RSDN, Владислав Чистяков (aka VladD2), недавно сделал забавное противопоставление себя со мной:

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


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

Пару раз жизнь меня сводила с людьми, с которыми мне практически не удавалось находить общий язык. Это еще один такой случай. Можно было бы плюнуть и забыть. Но тут удачным образом совпали две вещи. Во-первых, я считаю необходимым поправить приписанные мне убеждения. И, во-вторых, я уже давно хотел написать о программировании на бумаге, и о том, что способствует повышению производительности программиста.
 
Так уж получилось, что я оказался не стандартным человеком (даже на чисто физическом уровне, поскольку с ростом в 195 сантиметров, я очень четко понимаю, насколько я отличаюсь от среднего человека). Поэтому у меня со временем сложилось убеждение, что рассчитанные на среднестатическое большинство вещи, вряд ли подойдут мне так же хорошо. А посему, я стараюсь использовать то, что хорошо подходит именно мне.

После такой преамбулы можно перейти к обсуждению приписанных мне... ну, скажем, заблуждений.

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

Уже опубликовано:
Programming on paper
IDE?
Is C++ the best language?
Programmer's productivity
Add-on

воскресенье, 18 января 2009 г.

Две статьи о многопоточности, которые следует прочитать

Первая статья Hans-J. Boehm "Threads Basics". Очень хороший рассказ о том, что же из себя представляет многопоточность в современных условиях (многоядерные системы, переупорядочивание инструкций как на уровне компилятора, так и на уровне процессора). В статье определяются понятия sequential consistency и data races. Буквально на пальцах объясняется назначение такой штуки, как fence (барьер памяти), и рассказывается, в каких случаях она должна использоваться. В общем, сильная статья, которая раскрывает глаза на то, какая же это сейчас сложная штука - многопоточность.

В дополнение к этой статье имеет смысл прочитать FAQ, который поддерживается тем же Hans-J. Boehm и Paul McKenney. Но этот FAQ посвящен только C/C++. А так же в статье есть ссылочка на C/C++ библиотеку atomic_ops, которую разрабатывает автор статьи.

Вторая статья Herb Sutter  "volatile vs. volatile" коротко и четко описывает, чем же различаются volatile в Java/.Net и C++, а так же о том, чем будут различаться atomic-типы и volatile в будущем стандарте C++0x.

Так же по ходу разбирательства с упомянутыми выше статьями мельком ознакомился с еще одной статьей Hans-J. Boehm "Reordering Constraints for Pthread-Style Locks". Статья сложная, с леммами, теоремами и доказательствами. Я ее читал позно вечером, поэтому смог осилить только введение и заключение (в котором показано, насколько могут снизить производительность неразумно используемые fences (барьеры памяти)) :(.