Friday, October 29, 2010

code completion

Что больше влияет на качество программного продукта? Продуманность и мощь ядра, или отполированная до блеска функциональность фич для конечных пользователей? Очевидно, что многие фичи Решарпера были бы невозможными без мощной поддержки со стороны ядра, но также очевидно, что все достоинства космической архитектуры могут быть сильно испорчены неаккуратной реализацией фич. Хорошим примером листовой фичи, требующей особой аккуратности, является код комплишен.
Трудно подсчитать количество времени, которое потребовалось для того чтобы реализовать комплишен в C#. Думаю, что это многие месяцы работы.
Сейчас в Решарпере поддерживается более десятка различных языков, и во всех них хочется иметь такой же отшлифованный код комплишен как и в C#. Да, реализовывать его в разных языках будут разные люди, и задача у них будет сложнее, так как многие технологии, которые мы поддерживаем сейчас напрямую не используются нами, а значит продумывать поведение нужно будет буквально в воздухе!
Возможно ли создать такую инфраструктуру, в которой качественный код комплишен получался бы автоматически? В общем случае, думаю, нет. Тонкая настройка нужна. Но хочется сделать так, чтобы реализация для конкретного языка сводилась бы исключительно только к такой настройке.
Собственно, созданием общей инфраструктуры код комплишена я и буду заниматься в ближайшее время. Посмотрим, что получится.

Sunday, October 24, 2010

Conflicts page

Интересно, кто-нибудь читает что написано на страничке конфликтов при выполнении рефакторингов? Лично я их не читаю, и каждый раз расстраиваюсь, что опять надо нажимать 'next' и ждать. Да, я расстраиваюсь еще больше от осознания того, что к моменту показа странички с конфликтами рефакторинг уже отработал, но изменения не были применены к реальным файлам!
Объясняется все очень просто. Самый удобный способ найти возможные проблемы при выполнении рефакторинга - это попытаться его выполнить и в процессе выполнения запоминать, что и где не получилось поменять. В случае, если есть ошибки или предупреждения, необходимо откатить все изменения и показать отчет. Конечно, результаты самых тяжелых вычислений необходимо закэшировать, но в общем случае рефакторинг выполняется дважды.
Когда-то мы стремились к тому, чтобы выдавать конфликты во всех случаях, когда рефакторинг может привести к появлению некомпилирующегося кода. Используя схему с двумя проходами, мы без проблем можем справиться с любой неординарной ситуацией и выдать сообщение, но как это сообщение поможет выполнить рефакторинг пользователю?   

Thursday, October 21, 2010

мои студенты

У меня закончился осенний семестр, и я снова на работе по средам.
Курс, который я рассказываю, отличается наличием большого числа определений и теорем, что не свойственно большинству курсов по так называемому системному программированию. Да, называется этот курс: анализ потока управления программ.
Мне не нравится принимать экзамен. Я не умею ставить оценки и поэтому ставлю только зачет или незачет. Я не понимаю даже, что проверяется этим экзаменом? Ведь полне можно допустить, что у меня не получилось что-то рассказать или подготовить хороший конспект для тех, кто не ходит на пары? А значит я ставлю оценку самому себе?
В этом году студенты радовали меня. Несколько человек смогли до конца разобраться и в алгоритме Лэнгауэра Тарьяна и в расстановке фи узлов с использованием итерированной границы доминирования.
Сасибо всем, кто ходил на пары!
А вообще-то немного жалко, что мои студенты работают не в JetBrains. Интересно, почему?

Tuesday, October 19, 2010

Что не вошло в extract method?

Каждый раз, когда я пишу новую фичу, я вытаскиваю из под стола новый листочек и начинаю записывать туда все то, что еще хочется сделать. Очень люблю такие листочки. Особенно люблю пачку таких листочков, посвященных языку JavaScript, которая в данный момент лежит у мення на столе.
В простых ситуациях хватает одного листочка. Реализованные или пересмотренные записи зачеркиваются, новые дописываются, а фича, тем временем, становится лучше, и это прогресс, который легко наблюдать.
И вот, фича готова, а незачеркнутые записи остались. Что же останется за рамками нового extract method?
Первое, что я счел излишеством - это возможность создавать статический метод в любых обстоятельствах. Существует несколько способов избавиться от использования this, и соответствующие настройки тяжело умещаются в и без того перегруженную страничку extract method.
Да, часто так получается что некоторая функциональность не попадает в продукт просто потому, что она трудно выражается в пользовательском интерфейсе. Именно такая история случилась с возможностью передавать в качестве параметров выделяемого метода не только переменные, но и целые выражения. Действительно, часто выделение метода сопровождается созданием параметров из выражений в новом методе с последующим удалением неиспользуемых параметров. Получается, что часть кода мы выделили зря, так как в дальнейшем все равно перенесли его обратно в место вызова с помощью 'introduce parameter'. Как решить эту проблему в настройках рефакторинга 'extract method' я не знаю.
Следующая задумка не дает мне покоя. Представьте себе большой метод. Надо разбить его на несколько, но как это сделать? Хорошо бы уметь применять extract method к методу вообще, и пусть он сам решит, что тут лучше выделить. Какие могут быть кандидаты в этом случае? Последовательности операторов, выдающие одно значение? Повторяющиеся несколько раз? Придумать эвристики и, опять же, удобный интерфейс для выбора и точной настройки кандидатов задача интересная. Надеюсь еще вернуться к ней, когда нибудь.
Очень хотелось добавить возможность возвращать из метода tuple из нескольких значений. Более того, можно было бы создать новый класс и использовать его в качестве типа возвращаемого значения. Несмотря на то, что фича кажется довольно простой, в ее реализации будет немало нюансов.
Напоследок хочется заметить, что, сам по себе, диалог рефакторинга выглядит, мягко говоря, немого старомодно. Я уверен, что необходимо двигаться в сторону уменьшения количества настроек и, в конечном итоге, полностью отказаться от диалогов в пользу темплейтов или какой-то другой технологии. Необходимо сделать так, чтобы писать и изменять код было бы удобно в редакторе, а не полагаться на то, что кто-то будет разбираться, что значат настройки в диалоге. Так как подавляющем большинстве случаев никаких дополнительных настроек для выделения метода не требуется, необходимо сделать так, чтобы изменения было бы легко делать уже после того, как рефакторинг завершен.
Я уверен, что я написал вовсе не обо всех недоделках. Надеюсь, новые прекрасные идеи будут легко реализовываться в новой инфраструктуре и радовать наших пользователей и нас.

Saturday, October 9, 2010

Продолжаю выделять методы)

Ну вот, уже прошла неделя с того момента как я начал переписывать extract method. С одной стороны, это не так уж много, если брать в расчет относительную сложность рефакторинга, с другой стороны, мне немного обидно, что не удалось уложиться в одну неделю. Более того, для окончательной доводки требуется еще дня 3.
Модель этого рефакторинга очень проста. Все представляется в виде списка параметров, которые необходимо либо передать внутрь, либо возвратить, либо протащить через метод. Возвращаемое значение тоже является таким параметром. Бывают фиктивные параметры типа Boolean, которые необходимо возвратить из метода, чтобы восстановить поток управления в месте вызова. Из всего списка параметров выбирается наиболее подходящий кандидат для возвращаемого значения, остальные становятся обычными параметрами. В настройках, конечно, можно выбрать другое возвращаемое значение или сделать метод типа void. Именно от параметра, выбранного в качестве возвращаемого значения зависит то, как будет преобразован код выделенного фрагмента, и как будет сконструирован вызов нового метода.
Люблю, когда модель получается простой. Не могу сказать, что для меня сразу стало очевидно, что возможность выделить из кода подпоследовательность - это просто еще один 'out' параметр, который чаще всего по умолчанию становится возвращаемым значением.
В ситуации когда в настройках можно что-то менять, возникает вопрос - как тестировать поведение при различных параметрах? У меня есть любимый алгоритм для таких ситуаций. Не самый оптимальный, конечно, но работает на ура! Называется - полный перебор. Да, выбор возвращаемого значения, выбор сущности, которую создать, передавать или нет конкретные параметры - вариантов довольно много, но не смертельно. Нет ничего невозможного в том, чтобы перебраться все комбинации и посмотреть что получится. И никаких больше настроек для конкретного теста!

Friday, October 8, 2010

Что переписать?

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

Wednesday, October 6, 2010

Я пишу extract method

Вы когда-нибудь писали extract method? Я мечтал написать его с первого дня моей работы в жетбрэйнс. И до этого тоже мечтал, так что теперь чувствую как моя мечта постепенно начинает сбываться.

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

В первый же день написал решение глобальной задачи анализа потока данных дня определения того, что надо передать в метод и что оттуда возвратить. Думаю, каждый когда-нибудь слышал про чудесный алгоритм dfa. Я счастлив, мне удалось его использовать! Немного повозиться с лямбдами, не забыть про ref out параметры объемлющего метода, еще не забыть тысячу мелочей и уже проходят полторы сотни тестов! На третий день, как раз сегодня, рисовал формочку с кнопочками и галочками. Нарисовалось с десяток различных настроек. Может быть диалог не нужен вовсе? Нет... Мир к этому еще не готов. Со скрипом удается разместить все на том же пространстве на котором были и старые опции, но с одной оговоркой. Не удивляйтесь теперь если до странички с выбором параметров у вас спросят, а что, собственно, вы хотите получить? Метод, свойство или может быть конструктор?

Еще немного из задуманного... Возможность создать сразу статический метод. Да, да! а не зафигачить ли туда третью страничку ака make static, где и позволить почтенному пользователю насладиться всем разнообразием способов избавится от использований 'себя'? А как вам методы с yield return? Наверное только ленивый не пытался выделить подпоследовательность, разочароваться, написать баг... А любую ли подпоследовательность можно вынести в новый метод? А если там yield break? А если yield return есть, то иногда можно обойтись без ienumerable. Кстати, определить это в общем случае довольно интересная задача. И к тому же довольно простая. Добавим анализ yield return в чудесный dfa, и будем проверять, что каждый yield return выполняется ровно один раз. Люблю язык c# - с ним такая проверка делается за 2 строчки кода! В первой проверяем что на любом выходе мы прошли через какой-нибудь yield, во второй для никакой yield не предшествует никакому и даже самому себе!

Думаю, extract method может дать фору любому рефакторингу по количеству частных случаев, а сколько мы их нашли можно будет увидеть совсем скоро! Я говорю мы, так как большинство из них имеют свои корни в нашем багтрекере, где, между прочим, можно посмотреть и состояние дел в других рефакторингах. Extract method сейчас чемпион. 45 реквестов! А кто следующий?