Искусство программирования под Unix (и не только). Часть первая, «правило модульности»

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

    Unix-программисты выделяются на фоне этих «автоматизаторов окошек». В мире открытого ПО каждый может попробовать свои силы и в разработке системного «софта», и в сложных прикладных решениях. Достижения таких людей в мире открытого ПО доступны всем, и для меня они порой заменяют любые рекомендации. Потому что их работу видно.

    Есть ряд книг, которые, на мой взгляд, являются своеобразными «библиями» для тех, кто решил связать свое будущее с разработкой ПО. С одной из них я хотел бы начать цикл статей. Это книга Эрика Рейнмонда, «Искусство программирования под Unix». Я бы рекомендовал эту книгу не только тем, кто выбрал для себя открытые операционные системы. В основе лежит довольно универсальная философия, пригодная абсолютно всем, связавшим свою профессию с программированием.

    Эрик Реймонд выделяет 17 правил этой «философии». Я буду посвящать по одной заметке на каждое правило. Я постараюсь изложить эти концепции в максимально понятной, упрощенной и популярной форме, насколько это будет возможно.

    Начнем с самого первого правила — Правила модульности. Оно звучит так: «Простые блоки связывайте друг с другом ясными и понятными интерфейсами» (Rule of Modularity: Write simple parts connected by clean interfaces).

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

    Два примера из реальной жизни: 1) классический домашний ПК из системного блока и монитора 2) ноутбук. К примеру, на обоих погас экран. Причина может быть в чем угодно, как мы понимаем. Но в случае домашнего ПК легко проверить первое предположение: а работает ли монитор на другом компьютере? если не работает — причина в мониторе. Если да — причина в компьютере. Далее можно попробовать видеокарту на другом компьютере — и сразу понять, в ней дело или нет. Аналогично дело обстоит с клавиатурой, мышью…

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

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

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

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

    Когда-то давно, после института, я писал систему проектирования воздуховодов для рязанской компании Эковент. Там можно было создавать произвольную модель воздуховодов — труб с разветвлениями во всех трех измерениях. В какой-то момент пришлось полностью переделать всю программную часть, потому что она стала просто слишком сложной. Отдельные компоненты, отвечающие за изменение конструкции — такие как, например, добавление элемента, имели текстовый интерфейс в виде текстовых команд вида «add block width=100 height=100 depth=10». Разумеется, пользователя никто не заставлял набирать такие команды, для этого был отдельный графический оконный интерфейс, где он вводил ширину, высоту, глубину, но далее форма все равно преобразовывалась в команду. Это позволяло очень просто отлаживать сложные ситуации, когда нужно было создать сотню объектов и выполнить их отрисовку.

    В UNIX-мире уже давно изобретен один унифицированный интерфейс для командной строки, называется он “каналом” (pipe, |). Через каналы можно очень просто связывать разные программы, выполняющие одну, очень простую задачу. Например, есть утилитка, которая считает число строк, символов (wc), и утилитка, которая показывает на экран содержимое файла (cat). Поставив их друг за другом, мы можем получить, например, число строк в файле (cat file | wc -l). И таких “утилиток” уже разработано очень много. Возможность комбинировать их «на лету» помогает решить довольно сложные задачи буквально за секунды.

    В итоге, несколько простых советов — мои следствия правила модульности:
    • Каждый блок, программа, модуль должны делать только одну вещь и делать ее хорошо. Если цель, назначение блока начинает «размазываться», стоит задумываться о ее разделении на части.
    • Если есть возможность, выбирайте интерфейсы из числа промышленных стандартов (XML, HTTP, RPC, CSV, JSON) и ни в коем случае не выходите за их рамки.
    • Если можно упростить интерфейс за счет увеличения количества блоков — упрощайте. Пусть блоков будет больше, зато будет возможность тестировать их отдельно. Разумеется, нормально, когда блоки не сами по себе, а выстроены в иерархию.
    • Если можно упростить функционал блока, разбив его на более мелкие блоки, с более четкой выполняемой задачей, со стандартными интерфейсами, без заметного ущерба в производительности — разбивайте. Даже, если есть ущерб в производительности — тщательно продумайте, иногда им стоит жертвовать. «Железо» сейчас стоит дешевле.


    » Продолжение: правило ясности
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 50
    • +1
      немного запутано написано, но правильно всё, конечно же :)
      • +6
        принцип хороший, но насколько я помню книгу, там было очень важное замечание — не забывать про здравый смысл, ибо излишняя мелочность тоже вредит
        • 0
          Да-да, и пример с ноутбуком и десктопом показателен.

          Я вот пользуюсь ноутбуком, и ничуть не жалею, что не могу выдернуть видеокарту из него) Для меня, как потребителя, модульная система компьютера — излишняя мелочность. (я понимаю, что ноутбук тоже модульный. мы же утрируем.)
        • 0
          Жаль, что такой материал (и так) не преподают в большинстве университетов
          • 0
            Просто это никому не нужно:
            — большинство студентов нынче не особо рвутся что-то изучать
            — а те, кто изучают, как правило сами разыскивают необходимую информацию
            — при этом преподаватели в большинстве своем тоже не рвутся что-либо менять в устоявшейся программе
            — а те, кто рвутся, сталкиваются в определенными проблемами соответствия своей программы требованиям
          • +7
            Как раз именно за модульность я и люблю Unix-системы. Вот только при чём тут веб-разработка?
            • 0
              Тоже не понял.
              Предлагаю перенести сюда:
              habrahabr.ru/blogs/nix_coding/
              • 0
                Я тут недавно, не могу в хелпе найти ответ на вопрос — могу ли я опубликовать это сразу в двух блогах? это разрешено? или тут и в персональном блоге? Как-то кажется нелогичным это делать через копи-паст.

                Дата публикации после переноса останется прежней? грубо говоря, если я статью годовой давности перенесу в новый тематический блог, она же останется столь же глубоко, что и раньше, но уже в новом?
                • +2
                  Опубликовать можно только в одном блоге.
                  А дата публикации при переносе остается прежней, вроде бы.
                  • 0
                    но вот в веб-разработке оно смотрится слегка не в тему.
                    есть просто «разработка»: habrahabr.ru/blogs/development/
                    • 0
                      перенес, действительно место ему там
                      последующие статьи также будут там
                    • –2
                      В двух блогах — запрещено, это называется «кросс-пост». Надо поэтому делать перенос:

                      1) Подписаться на новый блог.

                      2) Отредактировать блогозапись, указав ей в качестве места публикации новый блог вместо старого.
                      • 0
                        перенес.

                        а в персональный и тематический — это тоже кросс-пост?

                        А в ленте в новом блоге статья ж не должна по логике появиться, так как у нее дата старая? в противном случае можно каждый день туда-сюда переносить, и она всегда будет сверху. Да, вряд ли такое возможно.
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • +6
                      Ага, модульность. Уникальные возможности plaintext-овых пайпов. Do one thing right.

                      Есть «модуль», перечисляющий процессы — называется ps
                      Есть «модуль», умеющий искать паттерны — называется grep
                      Есть «модуль», посылающий процессам сигналы — называется kill

                      Прекрасно. Как же нам найти процессы по шаблону и послать им сигнал? Наверное так:
                      ps | grep <options> | kill <options>

                      Хм, не совсем. Надо густо перемазывать все sed/awk. Но вдруг нам не хочется связываться с парсингом. ОК есть -C cmdlist: ps пытается делать работу grep, но делает это плохо (one thing right, да-да). Поэтому появляется pgrep, который умеет еще и регулярные выражения. Ок, ну дальше то все нормально да?
                      pgrep <options> | kill <options>
                      Уж это то точно должно работать. Правда, ведь?

                      Не так быстро. Теперь нужно обмазываться не только sed/awk, но еще и xargs. А если нам не хочется? Ну придется делать еще одну «one thing» — нам не привыкать. Итак, на сцене…
                      pkill — комбайн, включающий в себя целых ТРИ модуля. Просто потому, что не только каждый «модуль» по отдельности не справляется со своими задачами, но даже комбинации два-в-одном — тоже не особо помогают.
                      А есть еще killall и skill. А также pstree и top (последний в основном потому, что «модуль» sort хреново справляется с задачей сортировки выхлопа из «модуля» ps).

                      «Do as I Say Not as I Do» в чистом виде. А вообще забавно, берется прописная истина (недаром работы одного архитектора по шаблонизации и модуляризации так ценятся в CS с середины прошлого века), и легким движением руки приписываются себе (желательно еще приписать это ТОЛЬКО себе — но это не всегда возможно). Особый шик, если у тебя получается всячески нарушать эту прописную истину, но при этом убедить всех в том, что только ты ее и соблюдаешь.
                      • 0
                        Это не вполне честная логика, потому что искажается исходный посыл, после чего из искаженного посыла делаются следствия. Никто не говорил, что в мире юникс все идеально. И какой пример ни возьми — пайпы делают чудеса.

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

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

                        Ну и последнее: людям свойственно ошибаться, а эволюции — тем более. В юниксе ОЧЕНЬ МНОГО того, что какой-то студент плохо продумал, а потом это «прижилось» и стало стандартом. Особенно эти страдают протоколы. Поэтому я не писал в статье нигде, что там все идеально. Но, в целом средневзвешенный мозг разработчиков юникса был отформатирован правильно и хороших примеров все-таки больше. смотреть лучше на них.
                        • +3
                          Это был ответ на «Как раз именно за модульность я и люблю Unix-системы». Подразумевается неявное сравнение «с не-Unix-системами». Неоднократно встречал эдакий юникс-снобизм как раз таки в духе «в мире юникс все идеально».

                          негативные примеры нужно будет не искать специально, а из них будет построено вообще все
                          Самое забавное, что модульность не имеет отношения к юниксу, а имеет к программированию вообще (и не только программированию — модуляризация и использование шаблонов пришли в само программирование извне). Более того, как раз в юниксе такие примеры и не надо искать специально — таких примеров на каждом шагу. Недодумки с безопасностью (даже SUS сейчас стеснительно называет суперпользователя «appropriate privileges», но все равно уши торчат в виде chmod в том же стандарте), недодумки с моделью исполнения (вот список функций, связанных с СОЗДАНИЕМ единицы исполнения: fork, fork1, forkall, pthread_create, pthread_atfork, posix_spawn, posix_spanwp, execl, execle, execlp, execv, execve, execvp, fexecve, system, может еще чего забыл), недодумки с файловыми абстракциями (функции для ОТКРЫТИЯ/СОЗДАНИЯ файла: open, fopen, fdopen, creat, popen, opendir, fdopendir, tmpfile, mkdir, mkdirat, может еще чего — причем для каждой функции из этого зоопарка существует отдельная функция закрытия).

                          А ведь это самые базовые вещи, основы которых были заложены наверное еще до появления юникса. Что уж говорить о шелле и текстовых пайпах, настолько неудобных, что люди предпочитают создавать огромные комбайны, которые делают все в один проход (типа ImageMagick), дублировать функционал (как в приведенных выше примерах), создавать на лету «новые скрипты» (xargs, find — последний еще и дублирует функционал кучи утилит типа ls, grep, stat и пр) и используют десятки других ухищрений — все только для того, чтобы избежать использования пайпа.

                          Причем тот же SUS описывает весьма небольшую часть функционала: ничего не сказано о графической подсистеме, мультимедиа стеках, модели драйверов и пр… И вот в том же линуксе со всеми этими «расширениями» творится такой же бардак, как и в самом стандарте.

                          Второе, что искажается, это«блок должен выполнять только одну задачу»
                          Так это же из юникс философии. И необходимость текстовых пайпов — тоже оттуда.

                          Более того, как раз пример с ноутбуком некорректен. Ноутбук состоит из тех же шин и компонентов, что и «большие» компьютеры — просто они не всегда «user serviceable». Более корректным будет пример SoC.
                          • 0
                            Исправленные версии UNIX, в которых нет большинства из описываемых Вами недостатков, называются Plan9 и Inferno — но они так и не стали популярны за почти 20 лет. Ибо внутренняя простота и элегантность ОС уже давно никого не волнует. И в любом случае даже уродливый и переусложнённый POSIX будет по-проще надцати вариантов виндового API (впрочем, если Вы с этим не согласны, будем считать что я не прав в этом утверждении — разводить на эту тему флейм смысла нет).

                            Что касается sed/awk/xargs — я не вижу в их применении никакой трагедии. ps должен уметь выводить море разной информации, и разным программам дальше, в процессе выполнения канала, нужны разные элементы этой информации (grep-у имя команды, kill-у её pid). И гораздо проще и надёжнее пользоваться маленькими простыми кубиками делающими одну задачу и столь же маленькими и простыми склейками на sed/awk, чем большим, сложным и глючным комбайном. Тем более, что на практике в большинстве случаев в большом конвейере на 4-5 строчек применять sed/awk приходится пару-тройку раз, а не между любыми двумя командами. M$ попыталась решить эту проблему в powershell, передавая в канале объекты, но IMHO от этого легче, проще, лучше и удобнее писать конвейеры не стало.

                            Комбайны вроде pgrep/pkill и тонны опций у cat и ls появляются зачастую потому, что многие не пытаются следовать описанным в статье принципам — ибо в мире GNU некому бить по рукам пионерам, которые дорвались до возможности отправлять патчи и делать фичи. А в мире Plan9/Inferno этого нет — там cat -v considered harmful. Сравните, например, cat в Linux (12 опций) и в Inferno (0 опций), ls в Linux (57 опций, если я не сбился со счёта) и в Inferno (12 опций). Кстати, недавно в 9fans было прикольное обсуждение сложности команды cp (начиная с этого поста).
                            • 0
                              Ну а как по мне, правильные «исправления» пошли по другой ветке: VMS -> NT.
                              Ибо внутренняя простота и элегантность ОС уже давно никого не волнует.

                              Меня волнует. И именно поэтому я использую Windows.

                              И в любом случае даже уродливый и переусложнённый POSIX...

                              Ой, вот не нужно подменять понятия. В винде есть несколько унифицированных API для доступа к данным, в юниксах — нет вообще (есть отдельные врапперы для каждого отдельного языка программирования). Техническое поражение — команда не явилась на игру. Если уж сравнивать POSIX с чем нибудь, так это с Native API (которое одновременно и несравнимо полнее и несравнимо «стройнее»). А если говорить о Win32 API, то и сравнивать нужно с зоопарком *никсовых usermode библиотек (разных не только в разных ОС, но зачастую имеющих кучу разных версий под одну ОС).

                              Что касается sed/awk/xargs — я не вижу в их применении никакой трагедии

                              Сериализация в формат, не допускающий однозначной десериализации и собственный для каждой утилиты? Хм, действительно — никаких проблем.

                              Тем более, что на практике в большинстве случаев в большом конвейере на 4-5 строчек применять sed/awk приходится пару-тройку раз, а не между любыми двумя командами

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

                              M$

                              Сколько еще классов до поступления в институт?

                              попыталась решить эту проблему в powershell, передавая в канале объекты, но IMHO от этого легче, проще, лучше и удобнее писать конвейеры не стало.

                              Во-первых, компонентизация за счет объектов была в винде ЗАДОЛГО до powershell (лет 15 как минимум), а во-вторых таки стало. Пайп выглядит ИМЕННО как: ps | select | kill

                              Комбайны вроде pgrep/pkill и тонны опций у cat и ls появляются зачастую потому, что многие не пытаются следовать описанным в статье принципам

                              Ну ОК, давайте Вы приведете пример ps-grep-kill на чистом sh (следуя всем правилам), а мы сравним это с pkill (и с парой вариантов на PS, если захочется). pkill сотоварищи действительно появляются потому, что люди не хотят следовать некоторым юникс правилам, а не не хотят они потому, что не враги себе.
                    • 0
                      Насчёт последнего категорически не согласен. Одно дело, когда производительностью жертвуют в момент отрисовки экрана для пользователя, другое дело — в момент репликации.

                      Буквально недавно матерился на систему real-time репликации данных на ocaml'е. Объём данных, который можно было на 386 прокачать, жрёт гиг памяти и целиком (в один поток!) ядро довольно шустрого зеона.
                      • +1
                        Использование внутренних DSL — это вообще в мире CAD традиция возрастом в минимум лет 30. Не уверен, что найдется много CAD-ов, устроенных иначе.
                        • +5
                          Нихрена не понял. Модульность которой сто лет в обед, которая юзается везде, почему-то приплетена к юниксу, да еще и в блоге про веб разработку.
                          • +2
                            Вот вам не все равно к чему она прикреплена? Статья то не о том)
                            • +2
                              модульность приклеена к юниксу потому именно в нем она наиболее полно реализована
                              • 0
                                Вы с чем, простите, сравниваете?
                                • +3
                                  С plan9, вероятно.
                                  • +6
                                    с виндой, и программами под нее. В винде каждая программа — сама по себе. Все нужные библиотеки носит с собой. Если программе в винде требуется скачать файл с фтп, или создать архив — ей придется самой это реализовывать.
                                    В юниксах — программа при установке требует определенных зависимостей, и затем использует их ( вызов архиватора, или же curl для работы с фтп ). Так программы делаются легче, и не паряться решением побочных задач.
                                    • +2
                                      Есть разница между «наиболее полно» и «полнее чем в винде».
                                      • –7
                                        Я всего ожидал. Но то что вы говорите просто превысило все мои ожидания.

                                        Если программе необходимо скачать файл с FTP она делает WebClient.DownloadFile(«ftp://example.com/stuff.gif», «c:\\temp.gif»);

                                        Это .NET да-да. Модуль который распространяется с виндой уже лет восемь.
                                        Хочется из командной строки? System.Net.WebClient::DownloadFile(«ftp://example.com/stuff.gif», «c:\\temp.gif»); Пля, опять тот же модуль юзается? Хочется из КОМ? Хочется из анменджед? Хочется из SQL Сервер? Все есмь у меня. И все через этот модуль.

                                        Вы вообще на кого расчитываете чсо своим заявочками?
                                        • +3
                                          Модульность есть везде. Просто есть некоторая разница в культуре. Модульность в стиле unix way — это несколько принципов, обычно в мире windows не применяемых: использование текстовых протоколов, большое число маленьких процессов, общающихся друг с другом через пайпы, как можно более простая функциональность каждого из процессов.

                                          Сложно судить, какой из подходов лучше.
                                          • –2
                                            >> Модульность есть везде.

                                            Собсно я это и хотел сказать. Я привел пример, про модульность в винде. Она есть. Она не хуже (это просто не возможно определить). Она другая.

                                            Пайпы вообще не причем к модульности. Это не более чем протокол общения между программами. Что делать если в Винде пайпы в понимании юнихов не настолько важны? Ну нема там такого количества консолек. А между десктопными приложухами общаются просто другими протоколами. Месаджи, НеймедПайпы, Сокеты. Кстати в ПоверШел Майкры впедалили юниксоподобные пайпы.
                                            • +2
                                              Простите, но пайпы очень даже относятся к модульности. Это один из механизмов её реализации.

                                              Основное свойство пайпа — то, что можно всегда воткнуть что-то между двумя его концами. Например тот же netcat. Соответственно, такого рода модульность получается автоматически очень масштабируемой, и её намного проще отлаживать, поскольку протоколы преимущественно текстовые и понятные человеку.

                                              Конечно же у этого есть и обратная сторона — низкая производительность, проблемы с несовместимостью протоколов, сложнее инсталляция и конфигурация. Иными словами, реализацию модульности надо выбирать всегда под конкретную задачу, а не религиозно следовать чему-то одному, будь то Unix Way, [D]COM, CORBA, EJB и что угодно еще.
                                          • +3
                                            На секундочку:
                                            WebClient это класс, мы в программе создаём его экземпляр. Я правильно понимаю? То есть мы к своей программе прикручиваем функциональность фтп клиента (а на самом деле и не только фтп). В то время как мы могли бы использовать отдельную специализированную программу. Да, модульность есть. Но только внутри этакого комбайна. И разница лишь в том, что кучу библиотек за нами таскают другие.

                                            В никсах несколько иная идеалогия. В них изначально писались отдельные программы для выполнения отдельных функций. То есть была «внешняя» модульность, если это так можно назвать. Связано это с историческими причинами (мне кажется, что такая модульность — развитие идей разделяемых библиотек). Windows преследовал несколько иные цели изначально и его развитие шло несколько другим путём. Хотя, как показывает практика, винда приходит к тем же принципам, по которым никсы работают уже сейчас.
                                            • +2
                                              Предположим на юниксах вы пишете программу. Для того что бы скачать чето с ФТП, вы вызываете curl (отдельный бинарник). Что происходит в Винде. Вы вызываете функцию DownloadFile из бибилотеки System.Net (отдельный бинарник).

                                              Неужели это плохая модульность?
                                              • +2
                                                Не холивара ради, но…
                                                … а программа на Perl из-под Windows осилит DownloadFile?
                                              • +5
                                                curl в юниксах вы можете вызвать для всех языков, без ограничений: из bash-скриптов, из C и С++, из php/ruby/python, из java, из .net (mono приложений).
                                                В винде функцию DownloadFile вы можете вызвать адекватно только из .Net. Как это можно сделать из php/ruby, используя «голый» язык? Как подключить System.Net? А из C++ приложения? В этом и есть различия.
                                                • +2
                                                  >> DownloadFile вы можете вызвать адекватно только из .Net

                                                  Простите, я конешно понимаю что пост заминусованый сложно читать. Но там на русском языке перечислено, откуда DownloadFile можно вызвать нативно, без оберток. Еще раз PowerShell(прямой вызов любого стафа в .NET), COM(почти вся .NET BCL доступна как COM), SQL и AutoCad или любое другое приложение которое хостит CLR).

                                                  А теперь рассмотрим PowerShell, имея ее вы можете вызвать .NET из любого места которое может создавать процесы.

                                                  А теперь рассмотрим COM. Все что может создавать обьеткы (Javascript, VBA, 1C). Любой язык который может создавать обьекты.

                                                  Phyton, Ruby, тут две опции. Вопервых вы можете пользовать ихнее реализации под .NET. А можете как обычно воспользоваться COM (например поищите про win32ole).

                                                  Короче, я пока не могу придумать место из которого я не могу вызвать DownloadFile.
                                                • +1
                                                  Не плохая и не хорошая — просто другая. Для других задач.
                                              • 0
                                                Не кипятитесь, линуксоиды не следят за развитием современных технологий уже лет 10. У них на каждый чих давно по программе написано.
                                                • 0
                                                  Ну а что ещё остаётся делать, когда «современные технологии» реализуют принципы, которые в юникс-подобных системах были реализованы от самого рождения? ;)
                                      • +3
                                        да… Эрик Рейнмонд — это настоящая легенда опен сорс комьюнити!
                                        • 0
                                          хоть и без бороды
                                        • 0
                                          Все логично, по-моему, название статьи «Искуство программирования под Unix (и не только)....». Это актуально для никс? Актуально! И не только для Никс актуальна? Да, и не только для никс. Предполагаю будет очень интересный цикл статей, жду с нетерпением. Думаю для опен сорс это более значимо в следствии идеологии поддерживоемости кода.
                                          • 0
                                            Раз уж мы заговорили о *nix'ах, нельзя не упомянуть www.faqs.org/docs/artu/ch01s06.html. (Хотя что мы при этом делаем в блоге о веб-разработках?...).
                                            • +3
                                              wc -l file
                                              :)
                                              • –4
                                                Юникс рулит!
                                                • 0
                                                  Отличный пример на пальцах с десктопом и ноутом, однако, если переборщить с модульностью можно так же проиграть. Но про перебор — тема для отдельной статьи.

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