lex_kravetski: (Default)
Есть, знаете ли, такая фраза: «Иисус, спаси меня от твоих последователей». Удивительно, но к некоторым другим областям она тоже отлично подходит — в частности к так называемой «функциональной парадигме программирования».

В этой области явно существует какой-то закон, типа закона Бойцовского Клуба: «никому не говорить о Бойцовском Клубе», — но там он более изощрён: о Бойцовском Клубе говорить разрешается, но если кто-то, услышав о нём, вдруг решит в него вступить, то ему надо сразу же в ответ на простые вопросы задвинуть мощной метафизики со специальными терминами, которые он ни за что не поймёт, а ещё чуть-чуть пообщавшись с последователями, решит, что от этого вашего Клуба и от Иисуса вообще лучше держаться подальше.

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

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

Дальше )


lex_kravetski: (Default)
Данная статья не содержит никаких масштабных метафор, тонких ассоциаций или суровой сатиры. Поэтому интересна она будет только программистам. Да и то не всем.

Целью данной статьи является объяснение некоторого момента, который вызывает массу вопросов, а не обучение годному стилю написания программ и не рекомендация всё тут описанное в обязательном порядке использовать.


«Продолжения». Вопросы, что это такое, и зачем оно может понадобится Scala, имеются в изобилии практически в любом месте, где Scala обсуждается в постоянном режиме. А вот ответы на эти вопросы, напротив, почти не имеются.

Но если ответ всё-таки есть, то с вероятностью 99% им будет вот этот пример.

Дальше )
lex_kravetski: (Default)
Поставил эксперимент. Точнее, он сам случайно поставился.

Довольно простая задача. Есть массив (или какой-то ещё список) с элементами. Назовём его elements. Есть массив с несколькими индексами. Назовём его indices. Нужно получить новый массив, в который войдут те элементы из elements, индексы которых содержались в indices. Проще говоря, из полного набора элементов выбрать, скажем так, заселекченные.

Удивительно, но несколько моих знакомых программистов практически в один голос начали с примерно такого маршрута: будем итерировать от 0 до elements.size и для каждого номера проверять, есть ли он в indices. Если есть — добавлять соответствующий элемент в новый массив. Точнее, нет, будем итерировать по elements и увеличивать на единицу счётчик. Проверять, есть ли, добавлять текущий. Точнее, нет, добавим содержимое indices в Set, чтобы быстрее проверять.

Я и сам машинально пошёл сначала по этому маршруту — именно поэтому и решил провести подобный эксперимент. Почему так происходит — не знаю. Видимо, от сильной привычки извёрнуто итерировать.

Хотя на самом деле решение мега-тривиальное: итерируем по indices, и добавляем в новый буфер массива elements(indices(i)). Тривиальное, но приходит оно почему-то вторым по счёту, а не первым. «Снимаем чайник с плиты, выливаем из него воду и таким образом приводим задачу к уже решённой».

На Scala решение записывается совершенно очаровательной в своей простоте конструкцией.

indices map elements

Смысл в том, что поскольку массив indices — коллекция, для неё определена операция map. То есть, преобразование коллекции путём преобразования каждого её элемента при помощи переданной в аргумент функции. Но функция извлечения из скала-коллекции — это просто apply, то бишь, при вызове — просто индекс в скобках после имени переменной: elements(i).

Полная запись была бы такой:

indices.map(i ⇒ elements(i))

Однако для такого тривиального случая есть и сокращённый вариант записи. Приведённый выше. Имя ссылки на контейнер одновременно может выступать и как имя функции от одного аргумента с параметром типа Int.

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

Очевидное неочевидное.
lex_kravetski: (Default)
Кстати, придумал задачу для любителей запаха монад по утрам, да и вообще для заинтересованных.

Есть у нас данные на сетке. Для простоты они сложены в двумерный массив. Данные намерянны каким-то прибором, который мог сломаться, что мы, в частности, узнаём по наличию в любой точке сетки значения, превышающего заранее заданную величину maxValue. Нам надо выяснить, не сломался ли прибор как минимум по этому критерию, но не просто выяснить, а ещё показать любое значение, превысившее максимальное — чисто для пафоса. У вас-де вот в этой точке аж вот столько, чините прибор.

Решение задачи с императивным подходом просто и прозаично.

int value = 0; 
a: for (int x = 0; x < xSize; x++) {
    for (int y = 0; y < ySize; y++) {
        int v = data[x][y];
        if (v > maxValue) {
            value = v;
            break a;
        }
    }
}


Прозаично, понятно и правильно работает, но не круто. Круто написать то же самое не просто на Scala, но с for-comprehension или с использованием каких-то методов scala-коллекций и без break. При этом написать так, чтобы оно было короче и не имело существенных просадок по производительности в сравнении с данным конкретным примером.

Дерзайте, друзья.
lex_kravetski: (Default)
Большинство программистов, думаю, прочитав слово «Scala», среагируют в ответ термином «WTF?». Чуть менее значительная часть скажет «что-то такое слышал, но не представляю, зачем это нужно». И лишь совсем немногие смогут похвастаться знанием этого языка. Между последней и предпоследней группой находится группа заинтересованных, но сомневающихся, так что данная статья, увы, совсем для немногих.

Мне посчастливилось около полугода программировать на Scala, и теперь я таки могу авторитетно рассуждать о нюансах девелопмента на данном языке. Самое главное, я могу ответить на наиболее часто возникающий у заинтересовавшихся вопрос «а можно ли вообще на нём девелопить?». Что для прикола поразвлечься понятно можно, но писать-то что-то полезное, оно как?

В общем, авторитетно отвечаю. Можно. Все сомнения о том, что какие-то штуки не будут работать, всё развалится в самый последний момент, возникнут непредвиденные сложности с языком, будет чего-то важного не хватать и так далее, они логичны и обоснованы, однако эксперимент показал, в случае со Scala такого не происходит. За полгода разработки я не встретил ни одной непреодолимой сложности, всё работало, из Java вызывалось и так далее.

Свои нюансы были, но не фатальные. Самый большой, видимо, — смена API работы с контейнерами, которая имела место быть при переходе с версии 2.7 на версию 2.8. Да, в Скале обратная совместимость есть далеко не всегда, однако это не только минус, но и плюс. Строгая обратная совместимость мешает языку развиваться. Однажды принятое решение остаётся навсегда, хотя вероятность не угадать даже при очень напряжённой предварительной подготовке совсем даже ненулевая. Кто как не знаю, но я с трудом верю в реюзабельность очень старого кода. Лучше получить более качественный инструмент для нового кода, чем мучиться из-за того, что новый код всё так же трудно писать в тех местах, где он завязан на неудачный, хотя и историчный дизайн за ради того, что код пятилетней давности всё ещё компилируется на новых версиях компилятора.

Собственно, мой старый код с новыми стандартными библиотеками не компилировался, однако я всё исправил довольно быстро — благо, код был написан без копипэйста, поэтому править пришлось мало где.

А без копипэйста он был написан благодаря тому, что написан на Скале. Да, во всех языках предлагают копипэйстить по минимуму, но в большинстве случаев это не удаётся, даже если очень хочешь. В первую очередь потому, что в той же, например, Java (и в C++ тоже) некоторые вещи, будучи обёрнутыми во что-то некопипэйстное, занимают даже больше места, чем с копипэйстом. Когда есть способ написать вместо десяти строк одну, то возникает соблазн написать одну. Если вместо десяти строк «по уму» следует написать восемь или тем более пятнадцать, очень тяжело побороть желание временно скопипэйстить, а в никогда не наступающем «потом» всё исправить на «как надо».

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

Дальше )
lex_kravetski: (Default)
Разбирался со всяким разным и между делом написал ценную тулзу. Смысл тулзы такой: коллекция музыки у меня большая, поэтому хранить её целиком на коммуникаторе не получается. В результате приходится регулярно что-то туда заливать с целью послушать в дороге. Но чтобы залить, надо предварительно выбрать. А это делать обычно лень. Или даже некогда — ведь мысль, что надо бы накопировать музыки возникает в последний час перед отъездом и вдумываться уже некогда. В остальные же моменты вдумываться просто лень.

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

Тащемто, один раз настроил, а потом парой кликов закачиваешь.

В процессе разработки подумал, что неплохо было бы, если нажали «отмену» — стереть фрагмент недокопированного альбома. Реализовал.

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

Потом третий раз подумал: если в целевой папке что-то уже есть, то разумно копировать столько, сколько нужно для набора требуемого размера папки. Ибо если там, например, полгигабайта уже лежит, то скопировать ещё желаемый юзером гигабайт может и не получиться. Тоже добавил.

Теперь у меня есть мега-тулза. И желающие тоже могут её себе получить.

Работает только под Виндой (поскольку там используется SWT, а как сделать форк под все платформы, я ещё не разобрался), требует Ява-машину (обычно у всех уже установлено). Места занимает 26 мегабайт, поскольку вовнутрь сложены все библиотеки, от которых это дело зависит.

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

MobileMusic

У кого не запускается по причине наличия нескольких java-машин, можно сменить расширение файла с "exe" на "jar" и запустить при помощи выбранной вручную машины.



lex_kravetski: (Default)
Эта статья — о нюансах программирования на Java. Никаких смыслов, выходящих за рамки программирования, в статье нет. Не обессудьте.

Но посвящена она вопросу, который многих программистов беспокоит.


Предложим, у нас есть ArrayList, заполненный некими объектами. Ставится задача: удалить из этого контейнера все объекты, для которых не выполняется условие P(e) (под P(e) подразумевается некоторая функция, принимающая на вход ссылку на элемент контейнера и возвращающая booean).

Концептуально способы решения этой задачи распадаются на две группы:

1. Мы можем проитерировать по контейнеру, проверяя условие и вызывая у итератора remove для тех элементов, для которых условие не выполнилось.
2. Мы можем создать новый контейнер, а потом проитерировать по старому, добавляя в новый те элементы, для которых условие выполнилось. После этого ссылке на старый контейнер присвоить ссылку на новый.

Обобщённо эти подходы можно назвать «подход remove» и «подход filter». Или «remove» и «filter» для краткости.

Возникает вопрос: какой из подходов лучше всего использовать?

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

Поначалу возникает ощущение, что filter должен работать гораздо медленнее, чем remove. Ведь в случае с фильтром будет создан новый ArrayList, который будет расширяться по мере заполнения. Мы в общем случае даже не можем создать ArrayList с подсказкой размера — неизвестно ведь, сколько элементов в конечном счёте войдёт в результирующий контейнер. То есть, массив внутри ArrayList будет пересоздан несколько раз. Из этого вытекает, что подход remove использовать вроде бы выгоднее.

Однако многочисленные эксперименты показали: в идеальном случае remove работает быстрее фильтра примерно на 25%, в худших же случаях он может быть медленнее в десятки, а временами — в сотни раз.

Идеальный случай — это когда удаляется один-два элемента. В этом случае remove слегка опережает filter. При пяти-семи удаляемых элементах remove и filter работают с одинаковой скоростью. Дальше remove начинает катастрофически отставать.

Отчего это происходит? Рассмотрим происходящее.

Отчего же? )
lex_kravetski: (Default)
Граждане делятся ценными сведениями:

Давайте ка посмотрим на то как ведут себя программы при модульном подходе: есть некий модуль который содержит в себе управляющий код(точка входа в программу ....) она реализует две модели при модульном подходе это либо так называемые "поток преобразования" либо "Диспетчерская" в разных учебниках по технологии программированию их по разному называют, суть их же заключается в том что при "потоке преобразования" управляющий модуль вызывает модуль который выполняет основную работу, но перед этим может выполнить некоторые преобразования входных данных, но при условии что управляющий модуль знает какие имеются вспомогательные модули, это первый ключевой момент для обеих моделей при модульном подходе. УПРАВЛЯЮЩИЙ МОДУЛЬ МОЖЕТ ВЫЗВАТЬ ТЕ МОДУЛИ О КОТОРЫХ ЕМУ ИЗВЕСТНО!

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

(источник)


Вот так вот, друзья мои. С точки зрения современников, до наступления сегодняшнего дня был адский ад. «Модульное программирование», — не смотрите, что самим своим названием намекает на концепцию «модуля», — это когда каждая программа написана в стиле «волшебный метод». До внедрения ООП все писали только так. Все подсистемы взаимодействовали между собой строго через «УПРАВЛЯЮЩИЙ МОДУЛЬ, КОТОРЫЙ О НИХ ЗНАЛ».  И сам лично во всех подсистемах всё менял. Поскольку, системы подписки не существовало!!! Даже функция qsort, поди, сортировала только то, что было известно разработчикам стандартной библиотеки. И только так, как они хотели.

Мне завсегда нравятся оба замечательных подхода: объявить, что предки были умные, а мы все — дураки, и наоборот, объявить всех предков дураками, а себя лично — умным. Раз у предков не было ООП, разумеется никто из них не догадывался, что можно абстрагировать компоненты и локализовать взаимодействие между модулями.

Как тут строится логика рассуждений? «Я недавно прочитал книжку про ООП, а до того писал на Бейсике. Само собой, моя программа на Бейсике состояла из одного огроменного куска кода, без функций и подпрограмм. Но в книжке про ООП написано, что так писать плохо! А ООП позволяет писать хорошо! У предков не было ООП, следовательно, они наверняка писали, как я раньше на Бейсике. То есть, плохо писали».

Слава богу, положение исправилось.

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

(там же)


Вместе с объектным подходом, понимаете, к нам пришла Свобода и Демократия. Теперь подсистемы сами решают, реагировать ли им, как реагировать и зачем реагировать. Вот где успех-то: подсистема если хочет — делает, а если не хочет, так не делает. Тут вам уже не тоталитаризм, где Главный Управляющий Модуль навязывает угнетённым подсистемам свои правила. Фиг там. Любая подсистема может самовыразиться и, например, сделать всё наоборот. Ну, чтобы быть не такой как все. Неясно, правда, как при этом «Управляющий класс следит, чтобы каждая подсистема работала, как того требуется», но в этом как раз и зарыта самая-самая трансцидентальность. Подсистема реагирует как хочет, а Управляющий класс — следит. Так-то!

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

Уже, знаете ли, хочется внедрить либеральное программирование. Ну, например, ввести конкуренцию между трэдами за процессорное время. Продажу возвращаемых значений на бирже. Тендеры среди объектов за право предоставить требуемую объектом-заказчиком функциональность. Систему импичмента методу main. Написать, наконец, Декларацию Прав и Свобод инкапсулированных сущностей. И Невидимую Руку в качестве диспетчера последовательности исполнения.

Несогласные, надеюсь, согласятся, и Каспаров ещё скажет своё веское слово по данному поводу.



lex_kravetski: (Default)
Кто из товарищей функциональных программистов может внятно, на примерах рассказать, в чём суть концепции Continuations (не самого функционального программирования)? Есть ли случаи, когда решение через это дело (как оно переводится правильно, кстати?) лучше, чем через все остальные дела? Если есть, то можно ли на примере пояснить, чем лучше и как ей надо пользоваться.

А то через ассоциированные темы появился некоторый интерес, но в интернете информация скудна и невнятна. В тех местах, до куда дотянулся, написано настолько путанно, что даже я со своим опытом не понимаю. И не я один — местами сотни комментов приписаны к статье: «автор, ты вообще о чём тут написал? ни хрена ж не ясно!».

Если кто может прямо на языке Scala — вообще отлично. Но можно и своими словами.

Заранее благодарен.
lex_kravetski: (Default)
В своё время мой отец очень доходчиво мне объяснил, почему он никогда не ходит в туристические походы: «Я воевал четыре года в окопах. После этого идея ехать в лес с палаткой кажется мне несколько странной».

Теперь я так же объясняю сыну, почему я не использую линукс: «Я работал на множестве разных компьютеров, начиная с БЭСМ-4...»

(источник)



Ну, понеслась!
lex_kravetski: (Default)

Шаг первый



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

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

Кстати, а вот отличная идея: надо завести класс DeleteOnExit и ему передавать указатели — кандидаты на зачистку. DeleteOnExit мы будем заводить по значению, поэтому при выходе из функции он удалится — мы ж вышли из его области видимости. А в деструкторе DeleteOnExit мы напишем delete для переданного ему объекта.

Вот что значит знание языка: пока эти дебилы выворачивались, я, с моими знаниями, сразу сообразил, как сделать необходимое. Это потому что интеллект и руки прямые!


Шаг второй



Чего я тут подумал-то. Вот есть у меня класс. В его конструкторе создаётся десяток объектов. А потом они удаляются в деструкторе. Если я эти объекты оберну в мой DeleteOnExit, то ведь они тогда сами будут вместе с родительским объектом удаляться. А что, удобно. Вот что значит системный подход! Нашёл решение и сразу же его применил. Называется «повторное использование». Поняли, ламерьё, как надо-то? Это вам не быдлокодить, это — торжество разума.


Шаг третий



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

Согласился. Вышел на работу и сразу охренел. Нет, я, конечно, подозревал, что Фотошоп какой имеет более длинный код, чем моя утилита, отслеживающая изменения в директории, но что б настолько! Да такого размера код за всю жизнь не просмотреть, зараза. Это ж надо так много написать! Я ж теперь уже наверно не смогу каждый день все строки кода перепроверять. А у них тут в архитектуре, со слов главного программиста, бардак полный: здесь создали объект, туда на него указатель передали, а оттуда он ещё вон туда ушёл. По ходу, архитектурой эти лохи вообще не владеют.

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

Сделал функцию и вписал в неё мой DeleteOnExit. Ничего так. Подход рулит. Но во второй функции оказалось, что указатель на объект надо наружу передать. Хотел ведь поначалу отрисовку прямо у себя сделать, но главный программист сказал, что так нельзя, что у них для отрисовки целая иерархия объектов используется, и я должен в неё как-то свой объект передать. На хрена, интересно, им такая иерархия? Чего бы сразу на месте не нарисовать-то? Но спорить не стал. Не люблю конфликты

В общем, объект должен уйти в их иерархию. А где его тогда удалять прикажете?

Проанализировал задачу, снова поразился, как много у них всего написано. Понял, что DeleteOnExit тут не прокатит. Придумал: этот объект мы положим в хранилище объектов, которое я сделаю, а там каждый объект будет обёрнут в DeleteOnExit. При удалении хранилища, удалятся и все объекты в нём. А в функции объект будем класть в хранилище. Вот что значит — системный подход. Это вам не быдлокодить.


Шаг четвёртый



Читать дальше )
lex_kravetski: (Default)
Я вообще не автомобилист и автомобили не люблю, но тем не менее.

Приходите вы, значит, в магазин с целью прикупить автомобиль. До визита, конечно, что-то про современные модели почитали, да и на старых неоднократно ездить доводилось. Однако прямо перед входом взор ваш падает на некую машинку. С виду — ничего вроде, нормально. Тут к вам подбегает продавец и вежливо так спрашивает: «вам помочь?».

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

— Ну а как она в целом?

Продавец вам:

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

Вы, осторожно так:

— А зачем мне снимать кожух мотора прямо с водительского места?

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

— Так нет, зачем мне вообще пересобирать мотор? Я ж не изготовитель автомобилей, я на нём ездить хотел.

— Вы просто не понимаете пока идеологии этого автомобиля. Его идеология — Полная Свобода. Почти каждую деталь можно легко пересобрать. Кроме корпуса — корпус придётся купить новый, если собранное вами в него не влезет. Но остальное можно и очень быстро. Например, если включить третью передачу, нажать на плеере «предыдущий трек» и постучать по левой водительской двери, то сразу же открепится коленвал. Про это, конечно, надо помнить, но зато любое неудобство можно оперативно исправить. Настроить всё, так сказать, под себя. Не понравился коленвал — раз и заменили. Говорят, можно даже прямо на ходу. То есть, при прямых руках через некоторое время никаких неудобств не останется.

— А что, есть ещё какие-то неудобства, кроме открепления коленвала в результате весьма вероятной последовательности действий?

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

— Но а нельзя ли было в этом демонстрационном варианте сделать прямо сразу так, чтобы всего этого вообще не происходило? Неудобно ведь и опасно?

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

— Так, быть может, имело смысл сделать, чтобы они по умолчанию не падали, а желающие потом наоборот настроили бы выпадение стёкол? Я ж могу про это случайно забыть и не остановить опускание стекла в миллиметре от предела.

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

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

— Ну, если этот «шофёр» — прокладка между рулём и сиденьем, кто ж тут виноват? Не может подстроиться под этот замечательный автомобиль — дебил, значит. Таким за рулём, я скажу, вообще не место. Ему, идиоту, предоставили Полную Свободу, а он ещё жалуется. Ну что, тяжело разве запомнить про шип? Тяжело нажатие контролировать? Наконец, если не нравится, тяжело пересобрать что ли? Шип убирается элементарно: сто шестьдесят два раза на тормоз за шесть секунд с равными интервалами, потом слить масло до семи миллиметров от дна, прикрепить крышку багажника кверх ногами, разбить молотком плеер и вшить в обивку заднего сиденья икону Казанской Божьей Матери. После этого откроется доступ к шипу, запросто спиливаемому алмазной ножовкой в ночь на Ивана Купалу. Вместо этого всякие там пидарасы хотят себе кто БМВ, а кто шестёрку. Ноют: то не так, это не эдак. «А нельзя ли кожух мотора сделать неоткрепляемым»? «А нельзя ли прикуриватель разместить на приборной панели, вместо отсека для залива бензина»? «А нельзя ли выкинуть труп петуха, традиционно замурованного в левую пассажирскую дверцу»? Убогие, тупые твари, чтоб им в аду сгореть. Хрен ли нельзя-то? Можно! Возьми изоленту, да прикрути бензабак! Запаяй, блин, прикуриватель и вози с собой зажигалку, если не можешь запомнить, что при заправке следует обязательно выключить напряжение на прикуривателе, — чего уж проще?! Петух, етить, — это вообще история. Он нужен для совместимости с версией одна тысяча двадцать седьмого года. Не могут историю, блин, изучить, а рассуждать лезут. Ламерьё. Уроды криворукие, вот вы все кто.

— Извините, но при такой куче недостатков, чего вообще этот автомобиль мне даст, чтобы недостатки компенсировать?

— Во-первых, это не недостатки. Недостаток — ваша низкая квалификация и нежелание заучивать матчасть. Ваш генокод — это недостаток. Во-вторых, этот автомобиль можно разогнать до ста восьмидесяти, тогда как большинство остальных быстрее ста пятидесяти не ездят. В-третьих, у автомобиля есть Идеология. Он приучает вас к порядку и внимательности, дарует вам Полную Свободу. Поэтому, в-четвёртых, вы можете гордиться тем, что осилили езду на таком автомобиле. Вы возвысились над толпой быдловодителей, овладев таким сложным устройством. Вы доказали, что способны запомнить десятки тысяч мелких исторических фактов и нюансов — про шип, про петуха, и так далее, — что сделало вас По-Настоящему Эффективным Шофёром, тогда как остальные по ущербности своей пересели на… да что там стесняться, на быдломашины они пересели. Некоторые, при этом, пересели, даже не попробовав этот замечательный автомобиль, не разобравшись в нём, не вникнув в нюансы, не прочитав мануал, даже ни разу его не увидев. Оно, конечно, проще вот так тяп-ляп неглядя пересесть и ездить — когда мозгов-то нет, конечно же, мануал не осилишь. Таким только автоматическую коробку передач подавай, а как с нашей адвансед-морзянкой на сцеплении разбираться — «ой как сложно» сразу. В-пятых, наконец, вы при желании можете пересобрать свой автомобиль, чтобы он выглядел как шестёрка. Или даже семёрка. Ну не в точности, однако похожим бы стал. Ну, знаете, вот тут две полоски такие изолентой пустить — чисто ролс-ройс, издалека будет казаться. Кстати, вентилятор в нём отличный…


В сфере компьютерных технологий такое почему-то срабатывает.


P.S. Товарищи верно подметили, что подобное срабатывает и в области социально-экономических формаций. Не могу не согласиться.

P.P.S. Как странно. Написано про компьютерные технологии в целом, подразумевая технологии разработки, однако граждане в описанном уверенно опознают Линукс, страшно обижаются и сразу начинают отстаивать Настоящую Правду. Эдак дойдёт до того, что в ответ на слово «херня», будут первым делом писать «Неправда!!! Линукс — не херня!!!».

P.P.P.S Особенно, касательно предыдущего пункта, радуют комментарии вида «тут про Линукс всё неправильно». При том, что в статье слова «Линукс» вообще нет. Нет даже слов «операционная система». Как его, Линукс, удивляюсь, комментаторы опознают тогда? Самого слова нет, описано всё неправильно, но комментатор безошибочно вычисляет, что речь именно про Линукс. Чудеса.

P.P.P.P.S. Реакция многих столь впечатляюща, что я даже принял беспрецедентное решение никого в этой теме не банить (ну, кроме как за спам). Полная Свобода здесь, пацаны, — любой пидарас в комментах может явить свой светлый лик миру и ему за это ничего не будет. Кроме, разве что, пометки его комментария тайным кодовым словом, которое я никому не скажу.
lex_kravetski: (Default)
Чисто навскидку хочется сказать, что оптимальная программа — это та, которая работает максимально быстро. Самую малость поразмыслив, понимаешь, что надо бы дополнить: при этом ещё и правильно. Уже одно только это дополнение несколько портит всю очевидность ситуации. Действительно, которая программа оптимальнее, быстро работающая и дающая ошибку один раз на миллион или работающая чуть медленнее, но ошибающаяся раз на десять миллионов? Да хрен знает. Общего случая тут нет, есть только конкретные случаи с разными ценами ошибок, что и определяет как раз означенное понятие оптимальности.

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

Мини-алгоритм, типа сортировки массива вполне возможно написать без ошибок. Просто потому, что физически возможно за крайне небольшое время сто раз к ряду проанализировать каждую строку программы. Совокупность алгоритмов на сто тысяч строк кода физически невозможно внимательно проанализировать даже один раз. То есть, физически возможно — за сто лет, например, — но вот за короткий срок, увы…

Количество ошибок по отношению к длине кода возрастает нелинейно (за счёт роста количества взаимосвязей между логическими блоками). Таким образом, если исправление ошибок в коде из десяти строк потребует, скажем, десяти минут, то для тысячи строк это будет уже не тысяча минут, а, скажем, десять тысяч. Даже при архи-грамотном проектировании и написании кода мега-квалифицированным программистом, число ошибок в отношении к длине кода всё равно будет расти. Равно будет расти и время на их исправление. Это — первый аспект проблемы.

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

Таким образом, увеличение длины кода будет нелинейно увеличивать время на его разработку, вне зависимости от квалификации программиста. Да, у квалифицированного на всё вышеперечисленное уйдёт радикально меньше времени, чем у абы у кого, однако время это всё-таки уйдёт. И стоимость программы, как легко догадаться, в конечном счёте от этого дела будет зависеть напрямую.

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

Дальше )
lex_kravetski: (Default)
С тех пор, когда вообще додумались до того, что последовательность действий можно оформить в алгоритм, который к тому же выполнять не вручную, а отдать на выполнение компьютеру, утекло весьма много времени. И придумали в области написания программ преизрядно всякого. В том смысле, что не смотря на активный массовый быдлокодинг, отдельным гражданам всё-таки мечталось завязать с написанием одного и того же кода по сто раз на дню, от чего те стремились с нижних, близких железу уровней к уровням высоким, где накал абстракций особенно силён. И хотя такие абстракции зачастую сходу понять сложнее, чем if-else какой, в результате, после тренировки с ними всё равно как-то проще. И писать и думать. А ещё не только проще, но и меньше вдобавок.

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

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

Так вот, расскажу об одной такой абстракции. Самой, как мне кажется, выдающейся в плане своей универсальности и воспринятости обществом: контейнерах. Даже нет, что там контейнеры, об итераторах. Ими, как и контейнерами, пользуются почти все, но мало кто отдаёт себе отчёт, насколько широко ими можно воспрользоваться.

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

Сейчас какой язык ни возьми, везде в той или иной мере будут представлены списки. Есть даже язык, которые чуть не только за ради списков был разработан — Lisp. Он сам себе список и списком при этом погоняет. Читать, правда, очень неудобно, поскольку запись инопланетная, но, тем не менее, изрядным прорывом он был. А так, даже в Бейсиках этих ваших уже были массивы — частный случай коллекции.

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

Итератор — суть абстракция, обладающая тремя свойствами:


  1. Его можно связать с интересующим нас множеством
  2. Ему можно говорить «дай следующий элемент»
  3. И его можно спрашивать «есть ли следующий элемент?», чем, вкупе с п. 2, не исключено, добиться посещения всех элементов этого множества


Как это обычно выглядит в Java Читать дальше )
lex_kravetski: (Default)
Была, в общем-то, проблема. Юзаешь какой-нибудь софт, активно креативишь и всё такое, а потом раз и записать надо. Ты, соответственно, жмёшь «записать как», открывается диалог выбора папки и имени файла, ты там клик мышкой, диалог же — бабах и закрывается. В смысле, аварийно закрывается — падает. Падает и уносит за собой всё приложение на фиг. И твой нафигаренный потом и кровью файл тоже.

Я, конечно, новые файлы не особо активно создаю, да и падает по такому сценарию оно не всегда, однако всё равно неприятно. А ну как сделаешь что-то ценное с нуля? Его ж записать надо, вместо этого же всё на фиг упадёт. Ну и прочий дискомфорт вида «что-то не работает» тоже радости не доставляет.

Решение сей загадки я нашёл исключительно путём вселенского мега-прозрения. Более того, подозреваю, иным способом её решить и не удастся. Ибо по всем возможным запросам, хоть как-то связанным с темой, Гугл выдаёт исключительно ссылки на места, где эти вопросы заданы. А вменяемых ответов там нет. Как максимум — «диск проверьте».

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

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

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

Ну и это, с Виндой временами можно поразвлечься не хуже, чем с Линуксом.
lex_kravetski: (Default)
Воз, который был и ныне там чуть не полгода, стронулся, господа присяжные. Институт закупил наконец-то винду. Правда, не семёрку, а XP, ну да ладно. И хотя два дня ушло на установку и настройку (линукс таки пальнул в спину из последних сил — раздел под него был в линуксовой системе, а после переформата в ntfs никак не хотел под виндой становиться диском C), всё равно я уже второй день ощущаю себя как будто в раю. Это ж блин всё работает!!!

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

Билла Гейтса восславим.
lex_kravetski: (Default)
Есть строчка на языке программирования, предположим, Java:

for ( _ ; _ < 100; _ ) {

Какие, на ваш взгляд, символы следовало бы вписать по умолчанию на место подчёркиваний? А вдруг вы неправильно угадали, как быть? Как думаете, насколько часто угаданное не подходило бы пользователю, программирующему в столь догадливой IDE?

Какая информация в заполненной строке — лишняя?

Вдумчивый ответ на приведённые вопросы весьма способствует развитию, скажем так, программистско-дизайнерских навыков. И наглядно раскрывает аспекты концепции предельной автоматизации.
lex_kravetski: (Default)

Заинтересовавшимся программой ZBrush, кстати, рекомендую разыскать учебные видео-материалы от Digital Tutors (там, где все подумали, они есть). Очень наглядно и по делу даётся не только вводный курс, но и весьма продвинутый курс тоже (курсов у них много разных). Всё рассказывают и показывают. Если смотреть и сразу повторять на деле за рассказчиком, многое становится понятным очень быстро. Единственный минус — говорят по-английски. Но, во-первых, довольно разборчиво, а во-вторых, две трети понятно и без слов.

Рассказчик там в самом начале, когда рассказывает про сочетания клавиш, говорит на слух что-то типа «О'» (отрывистое «о» такое). Это он имеет в виду «Alt» — я сам не сразу догадался.

lex_kravetski: (Default)
Отличная статья обнаружилась — прямо как будто я написал. Однако же со следующего абзаца текст не мой.


ДЕНЕЖНАЯ МОТИВАЦИЯ В ПРОЕКТАХ РАЗРАБОТКИ ПО



Асхат Уразбаев, (askhat@scrumtrek.ru)

Допустим, у вас есть много денег и вы хотите вложить их повышение производительности ваших сотрудников.

Есть один простой способ. Платите сотруднику пропорционально производительности. Большой выхлоп - много денег. Малый выхлоп - мало денег. В соответствии с теорией Павлова у сотрудника выработается условный рефлекс и он будет брызгать слюной к каждой выплате.

Работает ли это? КОНЕЧНО! С токарями-фрезеровщиками, дворниками, продавцами и даже немного с учителями английского. А вот с программистами НЕ РАБОТАЕТ. И проблемы тут такие.


ПРОБЛЕМА ИЗМЕРИМОСТИ ВЫХЛОПА



Нету линейки для программиста. Аршином общим не измерить. У них особенная стать. Ведь что такое производительность программиста? Кол-во строчек кода за единицу времени? Бред! Копипейст или просто выбор инструментов и подходов может породить практически любое кол-во. Кол-во багов? Не ошибается тот, кто ничего не делает. Ничего не пишем - нету и багов. Кол-во исправленных багов? Так ведь никакого героизма в исправлении багов нет. Смысл в том, чтобы НЕ ПИСАТЬ багов. Не хватало еще поощрять за их исправление! Задачка на полчаса - написать утилиту, которая путем внесения багов в код и исправлением их после репорта от тестера максимизирует ваш бонус.

Дальше )

Profile

lex_kravetski: (Default)
lex_kravetski

April 2017

S M T W T F S
      1
2 345678
9101112131415
16171819202122
23242526272829
30      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 20th, 2017 08:40 pm
Powered by Dreamwidth Studios