Рисовать можно научить любого. Научить же передавать через рисунок свои чувства (а тем более, чувства других людей), практически нереально, этому необходимо учится самому, имея некоторый врожденный фундамент и желание/стремление.С утверждением о том, что рисовать можно научить любого, я, как несостоявшийся художник-самоучка, категорически не согласен. В процитированной мной фразе вообще есть внутреннее противоречие – по-моему, человек умеет рисовать только тогда, когда он рисунком может передать свои впечатления (будь то пейзаж, натюрморт или портрет). А то временами бывает, что все черты переданы в точности, а портрета нет – поскольку нет искорки в глазах или же какой-то характерной, неуловимой для зрителя черты – потому что художник не смог передать то самое впечатление. Тем не менее, данная аналогия хороша, если сравнивать обучение рисованию/живописи и программированию. Итак, начать нужно с того, что рисованию и программированию можно научить только тех людей, которые наделены природными способностями. Для рисования это какая-то особенность нервной или двигательной системы (а может их обеих в комплексе), благодоря которой рука художника точно исполняет команды мозга, в результате чего и формируется изображение. Плюс к этому чувство дистанции и перспективы. Для программирования нужна врожденная способность разбивать какое-то простое действие на произвольное количество мелких и еще более простых последовательных составляющих. Это у обычного человека операция рисования окружности с помощью циркуля выглядит одной неделимой операцией – берешь циркуль и рисуешь. А у программиста это целая серия шагов – поднести циркуль к линейке для выбора радиуса, раздвинуть ножки циркуля на нужное расстояние, поднести циркуль к нужному месту на бумаге, воткнуть ножку с иголкой в бумагу, повернуть циркуль на 360 градусов вокруг ножки с иголкой. Т.е., если природой способностей к рисованию или программированию не дано, ничего путного не получится. А если дано? А если дано, то процесс обучения – это, во многом, процесс тренировки, натаскивания. В рисовании на уровень инстинктов выводится владение, скажем, техникой штриховки. В программировании – способность написания циклов или разбиения одной большой функции на несколько мелких. А то и вовсе – способность набирать тексты в редакторе. И, если речь идет только о технике, то можно сказать, что вышколить любого имеющего природные способности человека до виртуозного владения техникой, в принципе, возможно. Это только вопрос времени. Хотя, нужно отметить, что на обучение программированию тратится гораздо меньше времени, чем на обучение рисованию. Ну да здесь можно сделать скидку на то, что в рисовании очень важна физическая тренировка – рука сама собой должна точно повторять нужные движения (штрихи, мазки). В программировании такое совершенное взаимодействие "мозг-рука" не требуется. Но техника (что в рисовании, что в программировании) не определяет успех усилий автора. Если мы рассматриваем какое-то художественное произведение, то мы рассматриваем три вещи: 1. Сюжет (идею). 2. Композицию (расположение фигур на рисунке или картине). 3. Исполнение (технику рисунка). Как я сказал выше, технике можно натаскать. Композиция, в принципе, так же может быть донесена до ученика в процессе обучения. Поскольку существуют яркие примеры того, что называется "правильной" композицией, "неправильной" композицией, "перегруженной" композицией и т.д. Хотя и здесь есть интересный феномен – иногда люди могут очень грамотно и красочно рассказывать теорию композиции, но на практике им не удается создавать удачные композиции в своих произведениях. Так что здесь так же есть фактор природных способностей – у кого-то чувство композиции заложено изначально, ему достаточно нескольких ярких примеров для того, чтобы подсознание выдавало готовые композиции. У остальных таких способностей нет. Но они могут пользоваться имеющимися примерами как образцами. А вот с сюжетом ситуация наиболее интересна. Я не знаю, можно ли как-то тренировать креативность, развивать способность выдумывать сюжеты. И сильно сомневаюсь в том, что это возможно. У меня всегда были проблемы с выдумыванием сюжетов. Подсмотреть готовый сюжет (особенно, если речь идет о пейзажах или портретах), это запросто. А вот родить что-нибудь вроде "Атомной Леды" или "Сон, навеянный полетом пчелы вокруг граната за миг до пробуждения", или "Предчувствие гражданской войны" Сальвадора Дали – уже нет. Не дано. И не обучиться этому.
Размышления и впечатления, которые не хочется держать в себе. О программировании в частности. Ну и о творчестве, и о жизни вообще.
понедельник, 29 декабря 2008 г.
Программирование и рисование
суббота, 27 декабря 2008 г.
SObjectizer: идея о том, как порционно извлекать данные из приоритетной очереди
пятница, 26 декабря 2008 г.
Why FP doesn't matter yet? ;)
easydiff f x h = (f(x+h)-f x) / h
Мозги приходится напрягать уже для того, что бы выделить разные синтаксические элементы (список параметров, места вызова функций). Нет, что бы записать нормально:
easydiff(f, x, h) = (f(x+h)-f(x))/h
Глядишь, и народ бы к ним потянулся :)
четверг, 25 декабря 2008 г.
Программистам нужны простые решения?
Будучи сам программистом, я не могу согласиться с таким утверждением. Мне не нужны простые решения. Простое решение, это, например, язык Oberon. Ну и где он, кто им пользуется? Даже Java и C#, которые начинались как гораздо более простые инструменты, чем C++, сейчас по сложности или приближаются к нему, или уже превзошли (в частности, C# 3.0 и готовящийся к выходу C# 4.0). Программистам нужны мощные решения. А мощность и простота редко идут рядом. Что действительно нужно, на мой взгляд, так это многослойное решение, которое можно изучать и применять, постепенно переходя от простого к сложному, как бы снимая слой за слоем. При этом обеспечивается легкое и быстрое получение первых результатов. По сути, человек быстро и незаметно подсаживается на иглу. После чего он вынужден либо изучать инструмент более тщательно, либо менять инструмент. Для достижения такой многослойности, как мне кажется, нужно придерживаться нескольких правил (все нижеследующее относится к инструментам, которые действительно делают что-то полезное): 1. Решение (инструмент) должно быть построено на основе небольшого количества простых идей и понятий. Например, SObjectizer в своей основе имеет только агентов с их состояниями, сообщениями и событиями. Все остальное, это надстройка над ними. 2. Решение (инструмент) должно быть снабжено хорошими обучающими материалами и документацией. Понятие "хороший", конечно же, субъективно. Но, например, изучать Ruby по книге "Programming Ruby" гораздо проще, чем C++ по книге "The C++ Programming Language". А все из-за того, насколько по-разному в каждой из книг построена подача материала – в одной идет плавное погружение человека в новый для него язык, а во второй – практически мгновенный переход к деталям. Поэтому что-то вроде Tutorial или Developer Guide с последовательным изложением тем от простого к сложному, это must have. При несомненной важности подобного обучающего руководства обязательно должно быть что-то вроде полного описания всех его классов, функций и пр. -- подробный Reference Manual. Поскольку очень обидно, когда после прочтения Tutorial-а пытаешься сделать что-то свое и негде найти список параметров какого-то метода. 3. Инструмент, если речь идет о более-менее серьезной библиотеке, должен иметь API нескольких уровней. Верхний уровень позволяет очень просто выполнять наиболее общие или наиболее востребованные действия. На этом уровне широко используются умолчания и пользователь, как правило, не имеет возможности делать какие-то тонкие настройки. Например, если какая-то операция полагается на использование пула потоков (thread pool), то пользователь не может указать какой именно пул потоков должен использоваться, сколько в этом пуле должно быть потоков, с каким приоритетом они должны работать и пр. Как раз такой верхний уровень API призван обеспечить легкое получение первых результатов у новых пользователей. Хороший пример – это параметры таких шаблонов, как std::vector, которые имеют значения по умолчанию. Вот, скажем, есть у std::vector такой параметр, как Allocator. А подавляющему большинству C++ программистов никогда не приходится его определять самостоятельно. Под верхним уровнем должно быть несколько более низких уровней, каждый из которых требует от программиста все лучшего и лучшего знания инструмента и понимания того, чего же программист хочет достичь. Но при этом программисту предоставляется все больше и больше возможностей. Ярким нарушением этого принципа, мне кажется, является библиотека Poco. В ней, к примеру, есть классы ActiveMethod и ActiveResult, которые используются для реализации фьючерсов. Но указать ActiveMethod, на каком именно пуле потоков должен выполняться асинхронный вызов метода нельзя. 4. Решение (инструмент) должно быть снабжено большим количеством примеров разнообразных способов его использования. Качественных примеров. Ведь зачастую фрагмент из примера посредством copy-and-paste переносится в код пользователя. Или же пример используется в качестве "рыбы" для программы пользователя. Обидно, когда библиотека содержит только примеры вида "Hello, world", либо не содержит примеров вовсе – в качестве таких примеров пытаются выдать unit-тесты. Хотя, например, в случае с ACE распространяемые с ACE тесты довольно часто оказываются вполне хорошими примерами и серьезно помогают во время изучения очередной возможности ACE. Но это, скорее, исключение. Не так уж и мало всего перечислил. Что, на мой взгляд, еще раз подчеркивает одно житейское наблюдение – не бывает простых решений сложных проблем. И для того, чтобы сделать что-то, что создает впечатление простого, нужно приложить немало усилий. Как замечательно сказал Алан Перлис:People thirst for simplicity. People need simple solutions to the problems that really matter: data access, code development, deployment, cloud computing, Web programming, and parallel programming, to name a few.
Simplicity does not precede complexity, but follows it.(источник).
среда, 24 декабря 2008 г.
Профессиональные убийцы времени
понедельник, 22 декабря 2008 г.
Так ли хорошо использование мейстрим языков программирования?
Больше десяти лет я программировал на самом мейнстримовом языке программирования последних двадцати лет - C++. И не сильно задумывался, хорошо это или плохо. Однако, по большому счету, мейнстримовым программистом я все-таки не был, т.к. изрядное количество времени я работал на экзотических платформах (например, OS/2 или OS-9000), и занимался не самыми типичными задачами (АСУ ТП, работа со SmartCard-ами через PC/SC ридеры, поддержка телекоммуникационных протоколов вроде SMPP и EMI). Познакомившись за последние несколько лет с целым рядом языков, которые не являются мейнстримом (например, D, Scala, Eiffel, Nice, Erlang, Ruby, OCaml), я стал более критично рассматривать полезность следования мейнстриму. В частности, на примере языков программирования.
Поскольку сейчас я несу ответственность за выбор конкретного инструмента для решения текущих задач компании, в которой работаю, то доводы "за" и "против" мейнстрима будут производиться с двух позиций. Во-первых, с позиции компании, которая нуждается в инструментах для разработки своих продуктов. И, во-вторых, с позиции разработчика, который не хочет остаться без куска хлеба, желательно с маслом.
Итак, чем же хорошо и чем плохо следование мейнстриму при выборе языка программирования?
Для компании использование мейнстримовых платформ хорошо тем, что, во-первых, нет проблем с наймом программистов: раз это мейнстрим, значит, есть достаточное количество людей, владеющей этой платформой. Во-вторых, нет проблем ни с инструментарием, ни с документацией, ни с техподдержкой. Для мейнстрим платформ существует большой выбор самых разных инструментов (компиляторов, профайлеров, IDE, библиотек и пр.). Огромное количество книг и on-line ресурсов, даже специальных обучающих курсов. Очень большое сообщество, в котором, при желании и настойчивости можно найти ответ на любой вопрос. В-третьих, мейнстрим либо означает возможность работать на большом количестве платформ (как пример кросс-платформенность Java), либо же работать на большом количестве компьютеров (как пример распространенность OS Windows, под управлением которой работает больше 95% всех персональных компьютеров в мире).
Т.е. для компании мейнстрим своего рода страховка, способ увеличить гарантии успешности выполнения своих проектов.
Для программиста мейнстрим это так же страховка. Пока ты в мейнстриме, ты имеешь хорошие шансы найти себе работу, если текущая по каким-то причинам не устраивает или же просто закончилась.
Теперь о том, какие риски есть у мейнстрима.
В первую очередь рассмотрим риски для компании.
Начать можно с того, что существует мнение о том, что каждые 10 лет появляется новый доминирующий язык программирования. Вроде того, что с 1986-го по 1996 -- это был C++, затем с 1996 по 2006 -- Java, с 2006 -- таковым MS хочет сделать C#. Так же меняются "горячие штучки" в самой индустрии. В 70-ые годы -- мейнфреймы. В 80-е -- развитие персоналок в одной нише и сетевых ОС (в первую очередь Unix-ов) в другой. С 1990-го по 2000-й было развитие desktop-систем (как раз в это время Windows стала доминирующей ОС). С конца 90-х до недавнего времени -- WWW, Web-системы и Web-программирование. Так же где-то с 2000-го активно развиваются ниши встраиваемых систем и мобильных систем (проще говоря, программирование для мобильников).
Так вот фокус в том, что какой-то новый язык/платформа не столько отвоевывает место под солнцем у уже существующих языков/платформ, сколько создает свои ниши. Так, на C++ никто не переписывал ПО мейнфреймов, а так же C++ не вытеснил полностью C из ниши системного программирования, зато на C++ была написана целая куча desktop-ного и middleware- (типа серверов баз данных) софта. Опять же Java не смогла вытеснить C++ из этой ниши.
А это значит, что простое следование мейнстриму может привести компанию к ситуации, когда на рынке образовалась новая "горячая штучка", но врубиться в нее на существующих технологиях не получится. Но, если компания живет за счет какого-то нишевого софта (типа наших систем мобильного банка или мобильной коммерции), то это не так страшно до поры, до времени.
Так же это означает, что если компания собирается выходить на рынок с новым продуктом, то правильный выбор будующего технологического лидера очень важен. Не очень разумно было вкладываться полностью в Java в 96-99-ых годах. Не очень разумно было вкладываться в C++ в 2004-2008-ых годах. Но, если с перспективной технологией угодать и начать ее использовать за пару лет до ее выхода в мейнстрим, то за счет этого можно получить чисто технические преимущества. Ведь каждая новая технология устраняет часть проблем, которая присутствовала у предшественников. Скажем, C++ добавил к C поддержку ООП. Java добавила к C++ безопасность, сборку мусора и дешевую кроссплатформенность. C# добавил к Java родную поддержку Windows и элементов функционального программирования. Т.е. переходя на новые языки/платформы, разработчики получают конкурентное преимущество перед теми, кто использует "старые" технологии.
Вот, например, сейчас стало модно обсуждать multicore процессоры. Оказывается, что очень сложно добится серьезного увеличения производительности программы при переходе на 2-х, 4-х и более ядерные процессоры. Часто наблюдается даже обратный эффект, на нескольких ядрах программа работает даже медленнее, чем на одном. Во многом в этом виноваты существующие подходы к разработке программ и существующие мейнстримовые языки программирования в частности. Появление новых языков, более приспособленных к параллельному программированию, или же встраивание специальных возможностей в существующие языки сможет дать серьезное преимущество при разработке хорошо масштабируемых программ.
Еще один аспект мейнстрима для компаний. Как известно, самое важное слагаемое успеха это люди. Несколько "правильных" людей способны производить больше качественного кода, чем несколько десятков(!) "неправильных" (по наблюдениям ДеМарко и Листера, да и не только их, разница в производительности между хорошими и плохими программистами может составлять до 10 раз). Но "правильных" людей, т.е. талантливых, увлеченных программистов, зачастую интересует то, что находится "на грани", что еще не попало в мейнстрим. Многие из них хотят применять то, что они считают перспективным и интересным. Поэтому, если дать им такую возможность, то это забавным образом повлияет на возможность найма людей: предложений на рынке будет гораздо меньше, зато качество предложений будет гораздо лучше.
Т.о. мейнстрим для компании это, с одной стороны, риск упустить шанс стать лидером при смене ориентации рынка. С другой стороны, не-мейнстрим это шанс получения преимуществ за счет новых технологий, но и риск проигрыша в случае "не выстрела" этих самых технологий.
Чем же плох для разработчика мейнстрим?
Главным образом конкуренцией на рынке труда. В особенности, при обвалах рынка, когда из-за массовых сокращений количество специалистов в какой-то технологии становится больше количества предложений. Хотя для хорошего специалиста работа, имхо, ищется не по технологиям, а по репутации и личным связям :)
Так же программисту нужно узнавать что-то новое и, желательно, не только в том, чем он занят на работе. Зашоренность всегда плоха. Тем более, что в программировании есть несколько совершенно разных ниш, каждая из которых требует своего инструмента. Например, для каких-то мелких, одноразовых задач хорошо подойдут скриптовые языки (типа Python или Ruby). Для desktop-приложений -- C++ (особенно для мелких, легких программ), C# и, отчасти, Java. Для server-side -- Java, C# и динамические языки вроде Erlang, Python, PHP и Ruby. Для встраиваемого ПО -- C, C++, Java, Ada. Для высоконадежного ПО с высокими требованиями к ресурсам и производительности -- C++, Ada, Eiffel. И т.д. Получается, что чем большим количеством хороших инструментов владеет программист, тем проще ему будет выбрать подходящий инструмент для какой-то из своих задач (если, конечно, у программиста есть выбор).