Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 17187 сообщений
Cообщения с меткой

java - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Что нового в IntellIJ IDEA 2016.3 EAP

Вторник, 30 Августа 2016 г. 14:14 (ссылка)

Вчера стала доступна IntellIJ IDEA 2016.3 EAP – программа “раннего” доступа к обновлению, запланированному на эту осень.



image



Для справки. Официально программа называется Early Access Program. На практике это аналог alpha-версии. Обновления появляются в среднем с недельной периодичностью. Каждый желающий может установить дистрибутив, попробовать новые функции и поделиться своим мнением и идеями в трекере.



В этом посте я расскажу о главных нововведениях, которые уже доступны в EAP-билде.



Отладчик



Class-level watches



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



image



Выражения указываются в контексте экземпляра класса.



Отображение примитивных типов



Теперь Java Type Renderers можно объявлять и для примитивных типов, включая массивы.



image



Анализ содержания памяти



С помощью нового плагина JVM Debugger Memory View, во время отладки вы можете исследовать содержание памяти.



Окно инструментов Memory View отображает количество экземпляров каждого класса. Чтобы открыть окно инструментов, воспользуйтесь главным меню: View -> Tool Windows -> Memory View.



Колонка Diff отображает как количество экземпляров изменилось с момента предыдущей остановки. Таким образом вы можете следить за созданием новых экземпляров.



image



Двойной клик на строчке класса откроет список экземпляров этого класса. Mark Object, Evaluate Expression, Add to Watches и другие операции отладки доступны применимы к любому экземпляру в этом списке.



image



Catch class filter



Следующее улучшение касается отладки исключений. Теперь вы можете задать границы Exception Breakpoint, указав пакеты, в которых это исключение ловится, – иначе говоря, в которых стоит try-catch выражение.



image



Контроль версий



Отмена коммита



Откатить последний неопубликованный коммит теперь можно одним кликом: выделите его в закладке Log и вызовите Undo Commit из контекстного меню. Действие эквивалентно команде “git reset --soft HEAD^”. Это значит, что изменения не пропадут, а перейдут в Local Changes.



image



Удаление веток



Теперь если вы удаляете локальную ветку, IDE предложит также удалить ветку, на которую она ссылается, либо откатить удаление.



image



Sign-off commit



Диалог Commit Changes теперь предоставляет опцию Sign-off commit.



File colors



Теперь в диалогах и окнах инструментов контроля версий каждый файл подсвечивается в соответствии с настройками File Colors.



image



Интерфейс



Recent tests



Теперь вы можете нажать Ctrl+Shift+; (Cmd+Shift+; для OS X) и увидеть список последних тестов. Список содержит как последние успешные конфигурации тестов так и неуспешные индивидуальные тесты. Enter–запуск теста; F4–переход к коду.



image



Текстовый поиск



Теперь, если вы вызываете Find in Path из редактора, настройки сохраняют указанные ранее значения, а не сбрасываются как раньше.



Java



Лямбда выражения в File Structure



Попап и окно инструментов Structure теперь могут показывать лямбда выражения, если соответствующая настройка включена. Включить ее можно нажав Ctrl+L (Cmd+L для OS X).



image



Некоторые интеншены стали инспекциями



Основное отличие инспекций от интеншенов заключается в том, что инспекции можно применить сразу на многих файлах. Мы выбрали ряд интеншенов, для которых это имеет смысл, и сделали из них инспекции: в частности Lambda can be replaced with anonymous class и Diamond can be replaced with explicit type arguments.



image



Настройки инспекции unused declaration



В инспекцию Unused declaration добавлены настройки Members to report. Теперь вы можете выбрать, на какие члены класса и модификаторы испекция будет распространяться.



Иерархия мета аннотаций



Окно инструментов Type Hierarchy теперь работает и для мета-аннотаций и позволяет видеть их иерархию. Это может быть особенно полезно для Spring или, например, JUnit 5.



JavaScript and CSS



Flow



Теперь, если вы указали Flow в качестве версии JavaScript, вы начнете получать сообщения о проблемах в коде прямо в редакторе для тех файлов, которые аннотированы "// flow".



image



Чтобы это работало, не забудьте указать путь к локально установленному Flow в Settings -> Languages & Frameworks -> JavaScript -> Flow.



Переименование методов в TypeScript



Переименование методов в TypeScript стало безопасным:




  • Если метод наследует или переопределяет метод из других классов/интерфейсов, IDE предложит переименовать базовые методы;

  • Если, существуют другие методы, переопределяющие или наследующие переименовываемый метод, IDE переименует и их.





image



Генерация кода Angular 2



Инструмент Angular CLI теперь интегрирован в попап Generate New, доступный по Alt+Ins (Cmd+N для OS X).



image



PostCSS



Для PostCSS теперь есть плагин. Установив плагин, вы получите подсказки, форматирование, навигацию, инспекции, переименование и другие функции предлагаемые для обычного CSS.



image



Группировка генерируемых файлов



В окне инструментов Project генерируемые файлы теперь группируются вместе с исходными файлами (если они в той же директории): например, ".css", ".css.map" и ".sass"; ".js", ".js.map" и ".ts"; и т.п.



Кроме нововведений обновление конечно же содержит массу багфиксов. Пока это все. Свежие EAP билды будут появляться каждую неделю.



Если обнаружите баги, пожалуйста сообщайте о них в наш трекер.



Ссылка на скачку EAP-билд: https://confluence.jetbrains.com/display/IDEADEV/IDEA+2016.3+EAP.



Буду рад ответить на вопросы.



Программируйте с удовольствием!
Original source: habrahabr.ru.

https://habrahabr.ru/post/308820/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Оптимизируем свои трудозатраты при разработке приложения в Google Material Design

Воскресенье, 28 Августа 2016 г. 18:04 (ссылка)



Данный материал может быть полезен как профессиональным дизайнерам интерфейсов, так и разработчикам, чьи познания в графических пакетах находятся ниже уровня “продвинутого пользователя”.



Итак, перед нами стоит задача: опираясь на готовые решения в открытом доступе, максимально оптимизировать затраченный труд на разработку приложения в стиле Google Material Design.



Стадия раз: прототипирование



Оно нужно, как минимум, для представления объемов приложения и состава экранов. Очень помогает в продумывании tap/click-путей (переходы между экранами). Я предпочитаю Axure, т.к. многие hot-keys сделаны 1 в 1 как в Adobe Photoshop (про остальные похожие продукты читайте в других статьях (в разделе “Дизайн” каждый третий пост на эту тему).



В него нужно установить три библиотеки:



Android_MaterialDesignV1.1 (Я.диск)



Достаточно навороченная библиотека, которая позволит составить прототип по всем гайдлайнам GMD. Особенность: многие элементы уже “приведены в действия”. Например pull to refresh работает сразу в скомпилированном html. Я думаю подойдет больше тем, кто хочет в прототипе уже “покликать”.





material-design-8 (Я.диск)



Более лёгкая и простая библиотека. Минимум готовых компонентов, но всё основное есть: чёрная и светлая темы, списки, карточки, кнопки, табы, диалоги, слайдеры и т.п… Отдаю ей предпочтение, так как чем меньше выбора, тем быстрее находится нужный элемент и перетягивется в прототип.





google-material-design-icons (Я.диск)



~750 векторных иконок от Google. Конечно можно использовать и дефолтный для Axure: Font awersome. Однако, реальные иконки придадут реальности прототипу.





Стадия два: дизайн



Как я упомянул выше, я отдаю предпочтение графическим пакетам Adobe. Значит нужно воззвать к дизайнерскому коммьюнити. Стоит поискать энтузиазтов, которые уже собрали GMD UI kit, в котором элементы расставлены и выглядят в соответствии со спецификацией гугла. Отступы, шрифты, размеры и т.п. Из бесплатных мне понравилось два:



sepia_ui_kit (Я.диск 142mb)





Есть всё необходимое, но мало кастомных идей. Тем не менее, прорисовано все экраны 1 в 1, которые сам Гугл использовал в своей официальной документации по GMD. Минус только в том, что долго искать по подпапкам нужный элемент в собственном отдельном исходнике.



Cooking (Я.диск 434mb)





Этот ui kit наоборот чрезмерно богат кастомными идеями. Но авторы немного перегнули планку. Явный педант в этом исходнике заметит, что как минимум интенсивность шрифта кое-где не совпадает с документацией. Есть немного графиков, фривольных кнопок. Поможет “скреативить” собственный элемент, но остаться в стиле.

Суперская навигация: из первью есть ссылка в отдельный исходник по каждому экрану. Достаточно сделать двойной клик. Просто прекрасно!



Стадия три: разработка



Ваш безответственный дизайнер не хочет отдавать все иконки отдельными файлами строго по спецификациям? Я Вас очень понимаю. Идите на materialdesignicons.com и спокойно скачивайте либо SVG с нужной иконкой, либо полноценный zip-архив с png под все разрешения смартфонов. Можно найти и не только сеты гугловских родных иконок. В базе много кастомных пиктограмм, выполненных членами дизайнерского сообщества. Как говорится “Это Бесплатно, и это всегда будет Бесплатно”. Непосредственно для девелоперов удалось вообще найти праздник готовых решений (github). Например таких:





Или вот таких:





Должно хватить…



Рад, если Вам пригодился этот пост! Ну а если хотите, почитать как я проецировал GMD на десктопный продукт и какие выводы сделал, то начните с первой части (всего их четыре).




Original source: habrahabr.ru.

https://habrahabr.ru/post/308684/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

О Legacy-коде без максимализма: что делать

Пятница, 26 Августа 2016 г. 16:45 (ссылка)





Представьте, что вам дали задачу поправить часть кода. В голове возникнет много мыслей. Кто его написал? Когда? А может он — legacy? Где документация? Давайте попробуем разобраться с «наследием» основательно и со всех сторон. Поможет нам в этом вопросе Андрей Солнцев @asolntsev (http://asolntsev.github.io/), разработчик из таллинской компании Codeborne. Начнём.



— Андрей, вы знакомы с трудами Michael Feathers, например, «Working Effectively with Legacy Code»? В книге акцентируется внимание на важности тестирования и выделяется одно из ключевых отличий legacy от не legacy-кода — это наличие тестов. Вы согласны с этим мнением?



Абсолютно согласен! Скажу больше: юнит-тесты — необходимое, но недостаточное условие. И с юнит-тестами можно навалить так, что сам Геракл не разгребёт.

Что для настоящего джедая мастхав, так это:


  1. TDD — то есть тесты ДО кода.


  2. Чистый код (и чистые тесты).






Я очень люблю книгу Robert C. Martin «Clean Code» («Чистый код»). Это для меня настольная библия. Категорически всем советую. Кстати, его блог тоже великолепен.





— С чистым кодом понятно. А при чём тут TDD? Код без багов — это ведь не то же самое, что хороший код?



Все думают, что TDD — это про тесты, а значит, это скучно.

Ерунда!

TDD — это про разработку (test driven DEVELOPMENT). Это способ создания кода таким, чтобы он был НЕ legacy. Таким, чтобы его было возможно поддерживать: отлаживать, исправлять, рефакторить, дорабатывать. На данный момент это единственный известный человечеству способ. Всё остальное — от лукавого, не дайте себя обмануть.



— Есть мнение, что TDD — для слабаков, а сильным разработчикам достаточно просто хорошенько пораскинуть мозгами и продумать код заранее. Тогда и багов не будет.



TDD нужен вовсе не для того, чтобы находить баги.

Тест — это первое использование твоего кода. Шерлок Холмс говорил: «Сначала собираешь факты, а уж потом выстраиваешь теорию. Иначе ты подсознательно начнёшь подтасовывать факты под свою теорию». Ты даже сам не заметишь, как это случится! Так же и с кодом: когда ты пишешь тест до кода, ты вынужден подумать о том, как его удобнее использовать, как назвать класс, метод; какие параметры передать. А если сначала написать код, то начнёшь подтасовывать тесты под него. В итоге доля тестов окажется слишком сложна, другая — трудна для исправления, а часть останется ненаписанной. И вот перед нами legacy-код собственной персоной!



— В продолжение разговора о тестировании — на ваш взгляд, какие тесты корректны и в каких ситуациях, например, юнит-тесты?



Начнём с юнит-тестов. Они необходимы в каждом проекте, тут без вариантов.



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



— А каким должно быть покрытие кода тестами? Достаточно ли 70%? Как не переборщить с «диагностикой» проекта?



Безусловно, нужно стремиться к максимальному покрытию. Все эти разговоры про 30% или 70% покрытие — от непонимания. Надо стремиться к 100% (хоть это и недостижимый предел).



Всем известно, что 100% покрытие невозможно, но не все правильно понимают, почему. Вовсе не потому, что «надо тестировать только критичное», «незачем тестировать геттеры» и «у нас есть дела поважнее».



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



Грубо говоря, если просроченные кредиты нужно подсвечивать красным, то логику «какие просроченные» нужно выносить в отдельный метод с юнит-тестами, а «подсвечивание» — отдельно. Ну там, css или как там ещё. И TDD стимулирует разделять эти слои, вот что замечательно. В этом его сила! А тесты — это лишь побочный эффект.



— Сколько времени нужно уделить созданию юнит-тестов, и на каком этапе проекта они играют ключевую роль?



Юнит-тесты играют ключевую роль всегда, на всех этапах. Нет такого этапа, где «пора начать писать юнит-тесты» или «можно больше не писать юнит-тесты».



Если делать всё правильно, вы никогда не сможете ответить на вопрос, сколько времени занимает написание юнит-тестов. Это часть разработки. Никто же не спрашивает, сколько времени занимает намазывание кирпича раствором, а сколько — укладка. Это всё необходимые шаги, и всё тут. Нельзя выкинуть один из них, иначе твоя стена развалиться на второй день, и ты получишь кучу legacy-кирпичей.



— Как у вас выглядит процесс написания тестов?



Ты пишешь красный тест 10 минут, делаешь его зелёным 10 минут, рефакторишь 10 минут. Никто, конечно, не замеряет это время точно — иногда это 5:30:0, а иногда 180:5:60. Неважно. Важно, что ты с таким же темпом, с предсказуемой скоростью сможешь менять код и через месяц, и через год. Постоянная скорость в долгосрочной перспективе гораздо важнее высокой мгновенной скорости на старте.



Советую вот это видео, где понятно и весело показано TDD: «Пацан накодил — пацан протестил!» Не пугайтесь длины, там про юнит-тесты только первые 30 минут.







— Андрей, если TDD так полезен, почему его так мало используют?



Всё просто. TDD — это дисциплина. Это как спорт: все знают, что спорт полезен, но ленятся. Самые честные признают, что им лень, остальные находят отговорки, а особо отъявленные начинают придумывать объяснения, почему спорт, оказывается, даже вреден. Так же и с TDD.



Забавная разница в том, что люди, лежащие на диванах, не называют себя спортсменами. Тут всё честно. А кодеры не пишут тестов и при этом называют себя разработчиками. Невероятно, правда? Но заканчивается это всегда одинаково. Спортсмен, пропускающий тренировки, быстро проигрывает соревнования. Так же и код, написанный не через тесты, моментально становится legacy. Тут всё честно.



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



TDD — это теорема, которую надо доказывать каждый день.



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



Я вам расскажу одну байку. Мой брат работал в химической лаборатории тартуского университета. К ним приехала делегация откуда-то из Европы. Им всё показали: новые помещения, новое оборудование, все дела. И тут они обратили внимание на старый советский агрегат где-то в углу. Делегаты сделали круглые глаза и спросили, мол, а что ж вы его не выкинете? На что последовал ответ: «Не поверите! Потому, что он… РАБОТАЕТ!»



Тут нет единого ответа. Можно ежедневно обновлять все зависимости и относиться к этому как к необходимой гигиене. Можно даже попросить Maven или Gradle делать это автоматически. А можно сделать fork оригинальной библиотеки и сидеть двадцать лет на старой версии. Пожалуй, это зависит от зависимостей. Если я сильно завишу от Selenium, использую новые фичи, то я его часто обновляю. Если я никак не завишу от новых фич log4j, я сижу на древней версии. Всё ж работает.



Чем старше я становлюсь, тем больше склоняюсь к тому, что не стоит гнаться за обновлениями. Новый Play framework оказался не лучше, чем Struts2. Maven не лучше (и даже хуже), чем Ant. TestNG однозначно хуже JUnit (а ведь «new generation» в названии!). Hibernate3 был сложнее, чем Hibernate 2. Spring boot сложнее, чем Spring MVC. А ведь лет 10 прошло! Про новые JavaScript библиотеки я уж молчу.



Так что не всё то новьё, что обмазано солидолом.



— В вашей практике встречались подобные ситуации (дополнительно к предыдущему вопросу)? Как вы выходили из подобных ситуаций? Какой стратегии вы придерживаетесь, переписать всё (часто используется термин — greenfield) или сделать рефакторинг?



Конечно, встречались.

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



Насчёт greenfield я довольно скептично настроен.

Конечно, плох тот солдат, который не мечтает всё переписать с нуля.

Но я за всю свою жизнь ни разу не видел, чтобы систему переписали с нуля и стало лучше. Обычно получается так же или хуже. Переписывальщик начинает с большим азартом, потом сталкивается с одной проблемой, с другой; понимает, что уже не успевает… Оставляет технический долг в одном месте, в другом — и вот у вас уже legacy-код в новом проекте, хотя ещё и половины-то не написано.



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



— Может быть, существует проверенный «гибридный» вариант?



Гибридный вариант есть. Можно переписать с нуля какую-то часть системы, самую легасисястую. Причём оставить старый вариант тоже, так чтобы они работали параллельно. И переводить на новый вариант все куски системы постепенно, один за одним. Да, это требует терпения и времени, но это единственный способ. Неохота? Тогда вообще не начинай. Торопыгам тут не место.



— Как вы отличаете плохой, попадающий под определение legacy-код, от максимально «разогнанного»? Стоит ли гнаться за производительностью в ущерб будущей поддержке?



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

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







— Как вы думаете, legacy-код может тормозить развитие всей системы?



Конечно, может! И тормозит!

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



— Вы можете дать совет о необходимости избавления от ужасного и медленного «монстра» в проекте, если его увидите? Как на это реагировали (если такие ситуации происходили)? Изменения провели к положительно эффекту (если такие ситуации происходили)?



Вероятно, вы слышали про правило бойскаута: оставляй поляну чуть чище, чем она было до тебя. То есть не просто поменяй нужную строку, но и отрефакторь чутка, допиши отсутствующий тест. Таким образом ваш проект будет постоянно улучшаться.



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



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



НО.

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



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



— Вы придерживаетесь мнения, что красота кода — это ещё не показатель legacy-статуса?



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



— Можно ли утверждать, что нарушение стандартного соглашения по оформлению кода — это legacy?



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



И не стоит ради них тратить свои силы. Настройте один раз IDE всех участников проекта, чтобы она сама форматировала код как надо, и больше не думайте об этом.



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



Конечно, менялось. Вначале я, как и все, думал, что плохой код пишут индусы и тупые коллеги. Или «джуниоры». Но всё не так просто.



Я не люблю слишком простые объяснения. Слишком легко свалить всё на «тех придурков». А legacy-код возникает и у самых умных людей, и в самых лучших проектах.



— И у тебя?



О да. О да!

Вот я тут вещаю, такой умный, про legacy-код, а у меня самого есть open-source проект Selenide, который legacy-кодом зарос по самое не моргну. Нет, он отлично работает, пользователи довольны, но мне его менять со временем всё сложнее. Есть тикеты, которые висят уже пару лет, потому что мне реально сложно их сделать. Поменяешь в одном месте — ломается в другом. Да, там есть интеграционные тесты, благодаря которым я не боюсь что-то сломать. Но от них нет помощи в том смысле, что менять-то код не получается.



Однажды я понял: ключевая проблема в том, что в этом проекте я изначально не писал юнит-тесты. Казалось, зачем тесты, если эта библиотека сама предназначены для написания тестов? Она и так будет протестирована вдоль и поперёк. А оказалось — вон оно что, Михалыч! Юнит-тесты нужны для избежания legacy-кода.



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



—Как вам кажется, в каких оттенках стоит воспринимать legacy-код? В каких случаях оправдано его наличие?



У меня есть простой рецепт. Отвлекитесь на секунду от лямбд и скобочек и представьте себя на месте клиента. Это здорово прочищает мозги.



Как клиент, привозите вы свою машину в автосервис, просите посмотреть, что там стучит.

А вам механик говорит: «Я поменял то, что стучало, но у вас ещё и топливный насос дырявый, — будем менять?» Это хороший механик. Плохой механик поменял бы насос сразу. А хороший механик сообщил о проблеме и расписал варианты: можно заменить сейчас — будет стоить столько-то. Можно не менять, тогда зиму ещё доездите, но потом и все шланги полетят — выйдет втрое дороже. И вы сами как клиент решаете. Один скажет: чего два раза ходить, меняй всё! Другой скажет: «Сейчас денег нет, а мне ещё зимнюю резину нужно. Давай до весны подождём».



А знаете, что сделает самый худший механик? Промолчит. Сделает только то, что просили.



А как ведём себя мы все с вами, дорогие программисты?

Те самые горячие головы, что норовят тут же всё порефакторить — они как кто? Правильно, как плохой механик. А те «повзрослевшие», что решают оставить всё как есть? Увы, как самый худший. А что должен сделать с legacy-кодом хороший механик? А как часто мы так делаем? Вот и думайте.



— Андрей, TDD, юнит-тесты — всё это звучит хорошо, но вы же понимаете, что для 99% наших читателей это неподъёмно в силу самых разных причин, часто от них не зависящих. А можете напоследок дать простой рецепт, как бороться с legacy-кодом?



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



Люди как люди. Любят торопиться, но ведь это всегда было… Человечество любит простые рецепты… В общем, напоминают прежних… микросервисный вопрос только испортил их…



В общем, волшебного избавления от legacy-кода не будет. Но вы держитесь там, удачи, хорошего настроения!



— Огромное спасибо за откровенную и позитивную беседу. Будем надеяться, что читатели откроют для себя, пусть и не простые, но все-таки решения в битве с legacy. Одна из недавних статей — прямое подтверждение важности тестирования. Лично меня вы убедили.



Спасибо и вам за приглашение.

А я воспользуюсь положением и приглашу всех читателей в гости к нам в Таллинн. У нас красивый средневековый город, хорошее крафтовое пиво и отличные мероприятия для айтишников, куда любой желающий может прийти бесплатно: devclub.eu



Спасибо за внимание и за терпение!






Больше интересных докладов, технических, хардкорных, вы найдете в программе Joker 2016. Если вы работаете с легаси, вам стоит обратить внимание на следующие доклады:





А также еще неопубликованный доклад Вячеслава Лапина «Как я переводил большой legacy enterprise проект на Java 8 — приёмы, трюки и «подводные ками»».

Original source: habrahabr.ru.

https://habrahabr.ru/post/308528/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

О Legacy-коде без максимализма: что делать

Пятница, 26 Августа 2016 г. 16:45 (ссылка)





Представьте, что вам дали задачу поправить часть кода. В голове возникнет много мыслей. Кто его написал? Когда? А может он — legacy? Где документация? Давайте попробуем разобраться с «наследием» основательно и со всех сторон. Поможет нам в этом вопросе Андрей Солнцев @asolntsev (http://asolntsev.github.io/), разработчик из таллинской компании Codeborne. Начнём.



— Андрей, вы знакомы с трудами Michael Feathers, например, «Working Effectively with Legacy Code»? В книге акцентируется внимание на важности тестирования и выделяется одно из ключевых отличий legacy от не legacy-кода — это наличие тестов. Вы согласны с этим мнением?



Абсолютно согласен! Скажу больше: юнит-тесты — необходимое, но недостаточное условие. И с юнит-тестами можно навалить так, что сам Геракл не разгребёт.

Что для настоящего джедая мастхав, так это:


  1. TDD — то есть тесты ДО кода.


  2. Чистый код (и чистые тесты).






Я очень люблю книгу Robert C. Martin «Clean Code» («Чистый код»). Это для меня настольная библия. Категорически всем советую. Кстати, его блог тоже великолепен.





— С чистым кодом понятно. А при чём тут TDD? Код без багов — это ведь не то же самое, что хороший код?



Все думают, что TDD — это про тесты, а значит, это скучно.

Ерунда!

TDD — это про разработку (test driven DEVELOPMENT). Это способ создания кода таким, чтобы он был НЕ legacy. Таким, чтобы его было возможно поддерживать: отлаживать, исправлять, рефакторить, дорабатывать. На данный момент это единственный известный человечеству способ. Всё остальное — от лукавого, не дайте себя обмануть.



— Есть мнение, что TDD — для слабаков, а сильным разработчикам достаточно просто хорошенько пораскинуть мозгами и продумать код заранее. Тогда и багов не будет.



TDD нужен вовсе не для того, чтобы находить баги.

Тест — это первое использование твоего кода. Шерлок Холмс говорил: «Сначала собираешь факты, а уж потом выстраиваешь теорию. Иначе ты подсознательно начнёшь подтасовывать факты под свою теорию». Ты даже сам не заметишь, как это случится! Так же и с кодом: когда ты пишешь тест до кода, ты вынужден подумать о том, как его удобнее использовать, как назвать класс, метод; какие параметры передать. А если сначала написать код, то начнёшь подтасовывать тесты под него. В итоге доля тестов окажется слишком сложна, другая — трудна для исправления, а часть останется ненаписанной. И вот перед нами legacy-код собственной персоной!



— В продолжение разговора о тестировании — на ваш взгляд, какие тесты корректны и в каких ситуациях, например, юнит-тесты?



Начнём с юнит-тестов. Они необходимы в каждом проекте, тут без вариантов.



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



— А каким должно быть покрытие кода тестами? Достаточно ли 70%? Как не переборщить с «диагностикой» проекта?



Безусловно, нужно стремиться к максимальному покрытию. Все эти разговоры про 30% или 70% покрытие — от непонимания. Надо стремиться к 100% (хоть это и недостижимый предел).



Всем известно, что 100% покрытие невозможно, но не все правильно понимают, почему. Вовсе не потому, что «надо тестировать только критичное», «незачем тестировать геттеры» и «у нас есть дела поважнее».



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



Грубо говоря, если просроченные кредиты нужно подсвечивать красным, то логику «какие просроченные» нужно выносить в отдельный метод с юнит-тестами, а «подсвечивание» — отдельно. Ну там, css или как там ещё. И TDD стимулирует разделять эти слои, вот что замечательно. В этом его сила! А тесты — это лишь побочный эффект.



— Сколько времени нужно уделить созданию юнит-тестов, и на каком этапе проекта они играют ключевую роль?



Юнит-тесты играют ключевую роль всегда, на всех этапах. Нет такого этапа, где «пора начать писать юнит-тесты» или «можно больше не писать юнит-тесты».



Если делать всё правильно, вы никогда не сможете ответить на вопрос, сколько времени занимает написание юнит-тестов. Это часть разработки. Никто же не спрашивает, сколько времени занимает намазывание кирпича раствором, а сколько — укладка. Это всё необходимые шаги, и всё тут. Нельзя выкинуть один из них, иначе твоя стена развалиться на второй день, и ты получишь кучу legacy-кирпичей.



— Как у вас выглядит процесс написания тестов?



Ты пишешь красный тест 10 минут, делаешь его зелёным 10 минут, рефакторишь 10 минут. Никто, конечно, не замеряет это время точно — иногда это 5:30:0, а иногда 180:5:60. Неважно. Важно, что ты с таким же темпом, с предсказуемой скоростью сможешь менять код и через месяц, и через год. Постоянная скорость в долгосрочной перспективе гораздо важнее высокой мгновенной скорости на старте.



Советую вот это видео, где понятно и весело показано TDD: «Пацан накодил — пацан протестил!» Не пугайтесь длины, там про юнит-тесты только первые 30 минут.







— Андрей, если TDD так полезен, почему его так мало используют?



Всё просто. TDD — это дисциплина. Это как спорт: все знают, что спорт полезен, но ленятся. Самые честные признают, что им лень, остальные находят отговорки, а особо отъявленные начинают придумывать объяснения, почему спорт, оказывается, даже вреден. Так же и с TDD.



Забавная разница в том, что люди, лежащие на диванах, не называют себя спортсменами. Тут всё честно. А кодеры не пишут тестов и при этом называют себя разработчиками. Невероятно, правда? Но заканчивается это всегда одинаково. Спортсмен, пропускающий тренировки, быстро проигрывает соревнования. Так же и код, написанный не через тесты, моментально становится legacy. Тут всё честно.



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



TDD — это теорема, которую надо доказывать каждый день.



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



Я вам расскажу одну байку. Мой брат работал в химической лаборатории тартуского университета. К ним приехала делегация откуда-то из Европы. Им всё показали: новые помещения, новое оборудование, все дела. И тут они обратили внимание на старый советский агрегат где-то в углу. Делегаты сделали круглые глаза и спросили, мол, а что ж вы его не выкинете? На что последовал ответ: «Не поверите! Потому, что он… РАБОТАЕТ!»



Тут нет единого ответа. Можно ежедневно обновлять все зависимости и относиться к этому как к необходимой гигиене. Можно даже попросить Maven или Gradle делать это автоматически. А можно сделать fork оригинальной библиотеки и сидеть двадцать лет на старой версии. Пожалуй, это зависит от зависимостей. Если я сильно завишу от Selenium, использую новые фичи, то я его часто обновляю. Если я никак не завишу от новых фич log4j, я сижу на древней версии. Всё ж работает.



Чем старше я становлюсь, тем больше склоняюсь к тому, что не стоит гнаться за обновлениями. Новый Play framework оказался не лучше, чем Struts2. Maven не лучше (и даже хуже), чем Ant. TestNG однозначно хуже JUnit (а ведь «new generation» в названии!). Hibernate3 был сложнее, чем Hibernate 2. Spring boot сложнее, чем Spring MVC. А ведь лет 10 прошло! Про новые JavaScript библиотеки я уж молчу.



Так что не всё то новьё, что обмазано солидолом.



— В вашей практике встречались подобные ситуации (дополнительно к предыдущему вопросу)? Как вы выходили из подобных ситуаций? Какой стратегии вы придерживаетесь, переписать всё (часто используется термин — greenfield) или сделать рефакторинг?



Конечно, встречались.

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



Насчёт greenfield я довольно скептично настроен.

Конечно, плох тот солдат, который не мечтает всё переписать с нуля.

Но я за всю свою жизнь ни разу не видел, чтобы систему переписали с нуля и стало лучше. Обычно получается так же или хуже. Переписывальщик начинает с большим азартом, потом сталкивается с одной проблемой, с другой; понимает, что уже не успевает… Оставляет технический долг в одном месте, в другом — и вот у вас уже legacy-код в новом проекте, хотя ещё и половины-то не написано.



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



— Может быть, существует проверенный «гибридный» вариант?



Гибридный вариант есть. Можно переписать с нуля какую-то часть системы, самую легасисястую. Причём оставить старый вариант тоже, так чтобы они работали параллельно. И переводить на новый вариант все куски системы постепенно, один за одним. Да, это требует терпения и времени, но это единственный способ. Неохота? Тогда вообще не начинай. Торопыгам тут не место.



— Как вы отличаете плохой, попадающий под определение legacy-код, от максимально «разогнанного»? Стоит ли гнаться за производительностью в ущерб будущей поддержке?



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

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







— Как вы думаете, legacy-код может тормозить развитие всей системы?



Конечно, может! И тормозит!

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



— Вы можете дать совет о необходимости избавления от ужасного и медленного «монстра» в проекте, если его увидите? Как на это реагировали (если такие ситуации происходили)? Изменения провели к положительно эффекту (если такие ситуации происходили)?



Вероятно, вы слышали про правило бойскаута: оставляй поляну чуть чище, чем она было до тебя. То есть не просто поменяй нужную строку, но и отрефакторь чутка, допиши отсутствующий тест. Таким образом ваш проект будет постоянно улучшаться.



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



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



НО.

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



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



— Вы придерживаетесь мнения, что красота кода — это ещё не показатель legacy-статуса?



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



— Можно ли утверждать, что нарушение стандартного соглашения по оформлению кода — это legacy?



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



И не стоит ради них тратить свои силы. Настройте один раз IDE всех участников проекта, чтобы она сама форматировала код как надо, и больше не думайте об этом.



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



Конечно, менялось. Вначале я, как и все, думал, что плохой код пишут индусы и тупые коллеги. Или «джуниоры». Но всё не так просто.



Я не люблю слишком простые объяснения. Слишком легко свалить всё на «тех придурков». А legacy-код возникает и у самых умных людей, и в самых лучших проектах.



— И у тебя?



О да. О да!

Вот я тут вещаю, такой умный, про legacy-код, а у меня самого есть open-source проект Selenide, который legacy-кодом зарос по самое не моргну. Нет, он отлично работает, пользователи довольны, но мне его менять со временем всё сложнее. Есть тикеты, которые висят уже пару лет, потому что мне реально сложно их сделать. Поменяешь в одном месте — ломается в другом. Да, там есть интеграционные тесты, благодаря которым я не боюсь что-то сломать. Но от них нет помощи в том смысле, что менять-то код не получается.



Однажды я понял: ключевая проблема в том, что в этом проекте я изначально не писал юнит-тесты. Казалось, зачем тесты, если эта библиотека сама предназначены для написания тестов? Она и так будет протестирована вдоль и поперёк. А оказалось — вон оно что, Михалыч! Юнит-тесты нужны для избежания legacy-кода.



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



—Как вам кажется, в каких оттенках стоит воспринимать legacy-код? В каких случаях оправдано его наличие?



У меня есть простой рецепт. Отвлекитесь на секунду от лямбд и скобочек и представьте себя на месте клиента. Это здорово прочищает мозги.



Как клиент, привозите вы свою машину в автосервис, просите посмотреть, что там стучит.

А вам механик говорит: «Я поменял то, что стучало, но у вас ещё и топливный насос дырявый, — будем менять?» Это хороший механик. Плохой механик поменял бы насос сразу. А хороший механик сообщил о проблеме и расписал варианты: можно заменить сейчас — будет стоить столько-то. Можно не менять, тогда зиму ещё доездите, но потом и все шланги полетят — выйдет втрое дороже. И вы сами как клиент решаете. Один скажет: чего два раза ходить, меняй всё! Другой скажет: «Сейчас денег нет, а мне ещё зимнюю резину нужно. Давай до весны подождём».



А знаете, что сделает самый худший механик? Промолчит. Сделает только то, что просили.



А как ведём себя мы все с вами, дорогие программисты?

Те самые горячие головы, что норовят тут же всё порефакторить — они как кто? Правильно, как плохой механик. А те «повзрослевшие», что решают оставить всё как есть? Увы, как самый худший. А что должен сделать с legacy-кодом хороший механик? А как часто мы так делаем? Вот и думайте.



— Андрей, TDD, юнит-тесты — всё это звучит хорошо, но вы же понимаете, что для 99% наших читателей это неподъёмно в силу самых разных причин, часто от них не зависящих. А можете напоследок дать простой рецепт, как бороться с legacy-кодом?



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



Люди как люди. Любят торопиться, но ведь это всегда было… Человечество любит простые рецепты… В общем, напоминают прежних… микросервисный вопрос только испортил их…



В общем, волшебного избавления от legacy-кода не будет. Но вы держитесь там, удачи, хорошего настроения!



— Огромное спасибо за откровенную и позитивную беседу. Будем надеяться, что читатели откроют для себя, пусть и не простые, но все-таки решения в битве с legacy. Одна из недавних статей — прямое подтверждение важности тестирования. Лично меня вы убедили.



Спасибо и вам за приглашение.

А я воспользуюсь положением и приглашу всех читателей в гости к нам в Таллинн. У нас красивый средневековый город, хорошее крафтовое пиво и отличные мероприятия для айтишников, куда любой желающий может прийти бесплатно: devclub.eu



Спасибо за внимание и за терпение!






Больше интересных докладов, технических, хардкорных, вы найдете в программе Joker 2016. Если вы работаете с легаси, вам стоит обратить внимание на следующие доклады:





А также еще неопубликованный доклад Вячеслава Лапина «Как я переводил большой legacy enterprise проект на Java 8 — приёмы, трюки и «подводные ками»».

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/308528/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Синий. Нет! Жёлтый! — или — Дают ли новые языки программирования прирост скорости разработки

Пятница, 26 Августа 2016 г. 15:03 (ссылка)

Какой язык использовали для написания самых первых программ для самых первых компьютеров с хранимой программой?


Двоичный машинный язык, конечно.



Почему?


Очевидно потому, что не было символьного ассемблера. Первые программы необходимо было писать двоичным кодом.



Насколько легче писать программы на ассемблере, чем на двоичном машинном языке?


Намного легче.



Можно цифру? Во сколько раз легче?


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



Экономия объёмов работы огромная.



Насколько? Можно цифру?


OK. Если бы я должен был написать простую программу, как, например, печать квадратов первых 25-ти целых чисел, в ассемблере на старой машине типа PDP-8, то мне потребовалось бы приблизительно два часа. Если бы я должен был написать ту же программу на двоичном машинном языке, это заняло бы вдвое больше времени.



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



Хорошо, достаточно. Таким образом, использование символьного ассемблера снижает объём работ в два раза?


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



Пожалуйста, поясните.


Хорошо, предположим надо изменить одну строку в программе на символьном ассемблере. Это займёт у меня 20 минут на старом PDP-8 с перфолентой. Но при ручном ассемблировании я должен затем пересчитать все адреса и реассемблировать все машинные команды вручную. В зависимости от размера исходной програмы уйдут часы. Последующий ручной ввод потребует не меньше времени.



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



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


Ладно. Полагаю, можно сказать, примерно в 10 раз.



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


Да, это, вероятно, близко к правде.



Если символьный ассемблер уменьшил трудоёмкость примерно в 10 раз, то насколько это сделал Фортран?


Очень прилично. Если мы говорим о 50-х, то Фортран тогда был простым. Иначе говоря, он был несколько больше, чем символьный ассемблер для символьной компоновки, — не уверен, понимаете ли вы, что я имею в виду.



Значит ли это, что он уменьшил трудоёмкость ещё в десять раз?


Что вы, конечно, нет! «Рутинная» нагрузка у символьного ассемблера не была такой высокой. Я бы сказал, что Фортран уменьшил трудоёмкость сравнительно немного. Возможно, примерно на 30%.



Иначе говоря, 10 программистов на Фортране могут заменить 13 программистов на ассемблере?


Если вы желаете рассматривать процесс с такой позиции, то да, похоже на то.



Продолжаем — насколько помогает сберечь время такой язык как С по сравнению с Фортраном?


Ну, С затрачивает немного меньше времени на «рутинную» работу, чем Фортран. В старом Фортране нужно было помнить такие вещи, как номера строк и порядок общих операторов. Было также невероятное количество операторов перехода по всему тексту. Язык С намного более комфортный для программирования, чем Фортран 1. Я бы сказал, что он уменьшил трудоёмкость примерно на 20%.



Хорошо. То есть 10 программистов на С могут заменить 12 программистов на Фортране?


Ну, это, конечно, только предположение, но я бы сказал, обоснованное предположение.



Хорошо. Теперь: насколько С++ уменьшил трудоёмкость по отношению к C?


Послушайте, давайте остановимся. Мы сейчас не вспоминаем о намного большем воздействии.



Разве? Что именно?


Среда разработки. Это значит, что в 50-х годах мы использовали перфокарты и бумажные ленты. Компиляция простой программы занимала, как минимум, полчаса. И то, если вы могли получить доступ к машине. Но в конце 80-х, когда С++ стал популярным, программисты хранили свои программы на дисках, а компиляция простой программы продолжалась уже всего две-три минуты.



Это — снижение трудоёмкости? Или просто уменьшение времени ожидания?


А. Так вот оно что. Вопрос ясен. Да, тогда машину приходилось ждать долго.



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


Понятно, понимаю. Итак, вы спрашивали о C++. Вообще-то, честно, я не думаю, что C++ как-то значительно снизил трудоёмкость. Конечно, что-то было, но, полагаю, не более 5%. Это значит, что рутинная нагрузка в С просто была небольшой, и поэтому сравнительная экономия времени при работе в С++ не могла быть значительной.



Если использовать 5%, то это значит, что 100 программистов на С++ могут заменить 105 программистов на С. Это, действительно, так?


В общем, да. Но только для небольших и средних по размеру программ. Для больших программ C++ даёт некоторые дополнительные преимущества.



Какие?


Это довольно сложно объяснить. Но суть в том, что объектно-ориентированные характеристики C++, в частности, полиморфизм, позволили разделять большие программы на независимо разрабатываемые и развёртываемые модули. И это — для очень больших программ — значительно уменьшает рутинную нагрузку.



Можно цифру?


Хорошо, вы, похоже, и дальше собираетесь выкручивать мне руки… Учитывая количество действительно больших программ, которые создавались в 80-е и 90-е годы, я скажу, что, в целом, C++ уменьшил трудоёмкость, возможно, на 7%.



Это не прозвучало особо уверенно.


Да. Но давайте использовать это значение. 7%.



Хорошо. Итак, 100 программистов на C++ могут заменить 107 программистов на C?


Похоже, так я и сказал. Давайте использовать это значение.



Сколько времени сберегает Java по сравнению с C++?


Трудно сказать. Какое-то время сберегает. Java — более простой язык. У него есть автоматическое управление освобождением динамической памяти («сборка мусора»). У него нет файлов заголовков. Он работает на виртуальной машине. У него есть много достоинств. И немного недостатков.



Как насчёт цифры?


У меня ощущение, что мы буксуем… Но поскольку вы так прессуете меня, то сказал бы, что при прочих равных условиях (чего никогда не бывает) можно, работая с Java, получить снижение трудоёмкости на 5% по сравнению с С++.



Итак, 100 программистов на Java могут заменить 105 программистов на C++?


Да! Впрочем, нет. Это не так. Разброс слишком большой. Если выбрать случайным образом 100 программистов на Java и сравнить их с так же выбранными 105 программистами на C++, то я не решился бы спрогнозировать результат. Чтобы получить реальный выигрыш, требуется намного больше программистов.



Насколько больше?


Как минимум, на два порядка.



Иначе говоря, 10 000 случайным образом выбранных программистов на Java могут заменить 10 500 так же выбранных программистов на C++?


Пожалуй, так.



Очень хорошо. Насколько такой язык, как Ruby, снижает трудоёмкость по сравнению с Java?


Ну, уважаемый! (вздыхает). О чём вы? Смотрите, Ruby, действительно, прекрасный язык. Он одновременно простой и сложный, элегантный и причудливый. Он намного медленнее Java, но компьютеры сейчас такие дешёвые, что …



Извините, но я спрашиваю не об этом.


Вы правы. Я знаю. Итак, главное направление, на котором трудоёмкость у Ruby меньше по сравнению с таким языком, как Java, — это Types (Типы). В Java необходимо создавать формальную структуру типов и поддерживать её согласованность. В Ruby можно играть с типами довольно быстро и свободно.



Звучит как прирост производительности труда.


В общем, нет. Оказывается, возможность играть быстро и свободно со структурой типа ведёт к появлению класса ошибок времени исполнения, которые отсутствуют при программировании на Java. Поэтому программисты на Ruby имеют более высокую нагрузку по тестированию и отладке программ.



Иными словами, эти эффекты уравновешиваются?


Это зависит от того, кого вы спрашиваете.



Я спрашиваю вас.


Ладно. Я бы сказал, что эффекты не уравновешивают друг друга. Трудоёмкость при работе с Ruby ниже, чем с Java.



Насколько? 20%?


Люди привыкли думать так. Действительно, в 90-е многие думали, что программисты на Smalltalk работают во много раз производительнее, чем на C++.



Вы запутываете меня. К чему вспоминать те языки?


Да потому, что C++ довольно близок к Java, а Smalltalk — к Ruby.



Ясно. Таким образом, Ruby снижает трудоёмкость в несколько раз по сравнению с Java?


Нет, скорее всего, не так. Если оглядываться на 90-е, то проблема со временем ожидания была ещё довольно выраженной. Длительность компиляции для типичной программы на C++ составляла несколько минут. Длительность компиляции для программы на Smalltalk была практически нулевой.



Нуль?


Практически, да. Проблема в том, что при использовании таких языков как Java и C++ необходимо выполнять много действий по согласованию всех типов. При использовании Smaltalk и Ruby такой проблемы нет. Поэтому в 90-е для них требовалось время от минут до миллисекунд.



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


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



Быстрая обратная связь снижает трудоёмкость?


Да, в определённой степени. Когда ваши циклы чрезвычайно короткие, то «рутинная» нагрузка в каждом цикла очень мала. Ваша занятость, вызываемая необходимостью отслеживания, снижается. Удлинение циклов увеличивает «рутинную» нагрузку, причём нелинейно.



Нелинейно?


Да, «рутинная» нагрузка растёт непропорционально длительности цикла. Она может расти как, например, O(N^2). Я не знаю. Но я совершенно уверен, что зависимость нелинейная.



Замечательно! Значит, Ruby является лидером!


Нет. И в этом-то суть. Благодаря совершенствованию нашего аппаратного обеспечения в последние двадцать лет длительность компиляции для Java стала практически нулевой. Время цикла у программиста на Java стало не больше (или должно быть не больше), чем у программиста на Ruby.



Уточните, пожалуйста.


Я говорю, что программисты, использующие дисциплину короткого цикла, увидят лишь небольшое различие в трудоёмкости (или, вообще, не увидят его), работая с Java и Ruby. Имеющееся различие будет настолько малым, что его трудно будет измерить.



Неизмеряемое различие?


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



Но вы раньше сказали, что Ruby снижает трудоёмкость по сравнению с Java.


Я думаю, что так оно и есть, но только если время цикла большое. Если цикл редактирование/компиляция/тестирование держать очень коротким, то эффект будет пренебрежимо малым.



Нуль?


Конечно, нет, — более вероятно около 5%. Но разброс будет гигантским.



Таким образом, 10 500 программистов, работающих в коротком цикле на Java, выполняют ту же работу, что 10 000 программистов в коротком цикле на Ruby?


Если добавить ещё один порядок для размера выборки, то я бы рискнул согласиться.



Существуют ли языки, превосходящие Ruby?


Можно получить ещё 5%, используя язык типа Clojure, поскольку он, с одной стороны, довольно простой, и, с другой стороны, функциональный.



Вы даёте лишь 5% функциональному языку?


Нет, я говорю, что дисциплина короткого цикла практически стирает различия по производительности в современных языках.



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



То есть: Swift? Dart? Go?


Не имеет значения.



Scala? F#?


Не имеет значения.



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


Не совсем так. Я говорю лишь, что мы идём по пути снижающейся эффективности. Ни один будущий язык не даст выигрыш в 10 раз, как это было у ассемблера по отношению к двоичному коду. Ни один будущий язык не даст снижение трудоёмкости на 50% или 20% или даже 10% в сравнении с имеющимися языками. Дисциплина короткого цикла свела различия к практической неизмеримости.



Тогда почему же появляются всё новые языки?


Это поиск Святого Грааля.



А, так это всего лишь вопрос уровня любимого цвета.





Примечание переводчика: Заголовок поста и его тематика являются отсылкой к фрагменту фильма «Монти Пайтон и Священный Грааль», в котором рыцари Круглого стола отвечают на пять три вопроса, чтобы пересечь Мост смерти
Original source: habrahabr.ru.

https://habrahabr.ru/post/308550/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Scala vs Kotlin (перевод)

Пятница, 26 Августа 2016 г. 11:10 (ссылка)

Наша команда, аналогично с автором статьи, уже почти как год перешла со Scala на Kotlin в качестве основного языка. Мое мнение во многом совпадает с автором, поэтому предлагаю вам перевод его интересной статьи.



Прошло прилично времени с того момента как я не обновлял блог. Вот уже как год я перешел со Scala, моего основного языка, на Kotlin. Язык позаимствовал много хороших вещей, которые мне нравились в Scala, сумев при этом избежать многих подводных камней и неоднозначности, которая есть в Scala.



Ниже я хочу привести примеры, которые мне нравятся в Scala и Kotlin, а также их сравнение в том, как они реализованы в обоих языках.



Объявление и выведение типов



Что мне особенно нравится в обоих языках так это то, что они оба являются статически типизированными с выведением типов. Это предоставляет вам возможность в полной степени воспользоваться мощью статической типизации без громоздких объявлений в коде (ориг.: declarative boiler plate). В большинстве случаев это работает в обоих языках. В обоих языках также прослеживается предпочтение неизменяемым типам вместе с опциональным объявлением типа переменной после ее названия.



Пример кода будет одинаковый в обоих языках:



Объявление неизменяемой переменной с именем age и типом Int:



val age = 1 


Объявление изменяемой переменной с типом String:



var greeting = "Hello"


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



Scala



val double = (i: Int) => { i * 2 }


Kotlin



val double = {i: Int -> i * 2 }


Data / Case классы



Scala и Kotlin имеют схожий концепт data классов, которые являются представлением data model object.



Подход в Scala


В Scala это case классы, которые выглядят следующим образом:



case class Person(name: String, age: Int)



  • Есть apply метод (не нужно использовать ключевое слово new при создание инстанса)


  • Методы для доступа объявлены для каждого property (если property объявлено как var то setter метод также будет присутствовать)


  • toString, equal и hashCode разумно объявлены


  • Eсть copy функция


  • Есть unapply метод (который позволяет использовать данные классы в pattern matching)




Подход в Kotlin


Kotlin называет данные классы как data class



data class Person (val name: String, val age: Int)


Ключевые особенности:




  • Методы для доступа объявлены для каждого property (если property объявлено как var то setter метод также будет присутствовать). Это не исключительная особенность data классов, утверждение справедливо для любых классов в Kotlin.


  • Разумно объявлены toString, equal и hashCode


  • Сopy функция


  • component1..componentN функции. По аналогии используется в качестве unapply.


  • Реализует JavaBean getter и setter, необходимых для таких Java фреймворков как Hibernate, Jackson, без изменений.




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



Сравнение



В основном case и data классы похожи.



Пример ниже выглядит одинаково в обоих языках:



val jack = Person("jack", 1)
val olderJack = jack.copy(age = 2)


В целом я нашел data и case классы взаимозаменяемым в повседневном использовании. В Kotlin есть некоторые ограничения на наследование data классов, но это было сделано из благих намерений c учетом реализации equals и componentN функций, чтобы избежать подводных камней.



В Scala case классы более мощные в pattern matсhing по сравнению с тем как Kotlin работает с data классами в ‘when’ блоках, в которых этого не хватает.



Подход Kotlin работает лучше для существующих Java фреймворков, т.к. они выгдядят для них как обычные Java bean.



Оба языка позволяют передавать параметры по имени и позволяют указать значению по умолчанию для них.



Null Safely / Optionality



Подход в Scala


В Scala null safely заключается в использовании монады option. Проще говоря, option может находится в одном из двух конкретных состояний: Some(x) или None



val anOptionInt: Option[Int] = Some(1)


или



val anOptionInt: Option[Int] = None


Можно оперировать с option при помощи функций isDefined и getOrElse (чтобы указать значение по умолчанию) но более часто используемая ситуация когда монады используется с операторами map, foreach или fold, для которых option представляет из себя коллекцию содержащую 0 или 1 элемент.



Для примера можно подсчитать сумму двух опциональных переменных следующим образом:



val n1Option: Option[Int] = Some(1)
val n2Option: Option[Int] = Some(2)
val sum = for (n1 <- n1Option; n2 <- n2Option) yield {n1 + n2 }


В Переменной sum будет значение Some(3). Наглядный пример того как for может быть использован как foreach или flatMap в зависимости от использования ключевого слова yield.



Другой пример:



case class Person(name: String, age: Option[Int])
val person: Option[Person] = Some(Person("Jack", Some(1)))
for (p <- person; age <- p.age)  {
  println(s"The person is age $age")
}


Будет напечатана строчка "The person is age 1"



Подход в Kotlin


Kotlin заимствует синтаксис groovy, достаточно практичный в повседневном использовании. В Kotlin все типы non-nullable и должны быть в явном виде объявлены nullable с помощью "?" если они могут содержать null.



Тот же пример может быть переписан следующим образом:



val n1: Int? = 1
val n2: Int? = 2
val sum = if (n1 != null && n2 != null) n1 + n2 else null


Это намного ближе к Java синтаксису за исключением того, что Kotlin принудительно выполняет проверки во время компиляции, запрещая использовать nullable переменные без проверки на null, так что можно не бояться NullPointerException. Также нельзя присвоить null переменной объявленной как non-nullable. Помимо всего компилятор достаточно умный, чтобы избавить от повторной проверки переменной на null, что позволяет избежать многократной проверки переменных как в Java.



Эквивалентный Kotlin код для второго примера будет выглядеть следующим образом:



data class Person(val name: String, val age: Int?)
val person: Person? = Person("Jack", 1)
if (person?.age != null) {
 printn("The person is age ${person?.age}")
}


Или альтернативный вариант с использованием "let", который заменает "if" блок на:



person?.age?.let {
 person("The person is age $it")
}


Сравнение



Я предпочитаю подход в Kotlin. Он гораздо более читабельный и понятный, и проще разобраться что происходит в многократных вложенных уровнях. Подход Scala отталкивается от поведения монад, который конечно нравится некоторым людям, но по собственному опыту могу сказать, что код становится излишне перегруженным уже для небольших вложений. Существует огромное количество подводных камней у подобного усложнения в использовании map или flatMap, причем вы даже не получите предупреждение при компиляции, если вы делаете что-то не так в мешанине из монад или используя pattern match без поиска альтернативных вариантов, что в результате выливается в runtime exception которые не очевидны.



Подход в Kotlin также уменьшает разрыв при интеграции с кодом Java благодаря тому что типы из нее по умолчанию nullable (тут автор не совсем корректен. Типы из Java попадают в промежуточное состояние между nullable и not-nullable, которое в будущем можно уточнить), тогда как Scala приходится поддерживать null как концепт без null-safely защиты.



Функциональные коллекции



Scala, конечно, поддерживает функциональный подход. Kotlin чуть в меньшей степени, но основные идеи поддерживаются.



В примере ниже нет особых различий в работе fold и map функций:



Scala



val numbers = 1 to 10
val doubles = numbers.map { _ * 2 }
val sumOfSquares = doubles.fold(0) { _ + _ }


Kotin



val numbers = 1..10
val doubles = numbers.map { it * 2 }
val sumOfSquares = doubles.fold(0) {x,y -> x+y }


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



Scala



val numbers = Stream.from(1)
val squares = numbers.map { x => x * x }
val evenSquares = squares.filter { _%2 == 0 }
println(evenSquares.take(10).toList)


Kotlin



val numbers = sequence(1) { it + 1 }
val squares = numbers.map { it * it }
val evenSquares = squares.filter { it%2 == 0 }
println(evenSquares.take(10).toList())


Implicit преобразования vs extension методы



Эта та область в которой Scala и Kotlin немного расходятся.



Подход в Scala


В Scala есть концепция implicit преобразований, которая позволяет добавлять расширенный функционал для класса благодаря автоматическому преобразованию к другому классу при необходимости. Пример объявления:



object Helpers {
 implicit class IntWithTimes(x: Int) {
   def times[A](f: => A): Unit = {
      for(i <- 1 to x) {
f
      }
   }
 }
}


Потом в коде можно будет использовать следующим образом :



import Helpers._
5.times(println("Hello"))


Это выведет "Hello" 5 раз. Работает это благодаря тому, что при вызове функции "times" (которая на самом деле не существует в Int) происходит автоматическая упаковка переменной в объект IntWithTimes, в котором и происходит вызов функции.



Подход в Kotlin


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



fun Int.times(f: ()-> Unit) {
 for (i in 1..this) {
   f()
 }
}


5.times { println("Hello")}


Сравнение



Подход Kotlin соответствует тому как я в основном использую данную возможность в Scala, с небольшим преимуществом в виде чуть более упрощенной и понятной записи.



Особенности Scala которых нет в Kotlin и по которым я не буду скучать



Одна из лучших особенностей Kotlin для меня даже не в том функционале что есть, а больше в том функционале которого нет в Kotlin из Scala.




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


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


  • Перегруженный for — Проблема с несколькими монадами, показанная выше.


  • Беспорядок с опциональным синтаксисом infix и postfix операторов — Kotlin чуть более формализованный. В результате код в нем менее двухсмысленный,  его проще читать и не так легко простой опечатке стать неочевидной ошибкой.


  • Переопределением операторов по максимуму — Kotlin разрешает переопределение только основных операторов (+, — и т.п.). Scala разрешает использовать любую последовательности символов. Действительно ли мне нужно знать разницу между "~%#>" и "~+#>"?


  • Медленное время компиляции.




Спасибо за внимание.

Оригинал Scala vs Kotlin

P.S. В некоторые местах в переводе специально оставил слова без перевода (null, null safely, infix, postfix и т.п.).


Original source: habrahabr.ru.

https://habrahabr.ru/post/308562/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
tofrar

Без заголовка

Пятница, 26 Августа 2016 г. 13:36 (ссылка)

Еще одна вещь, которую надо сохранить, чтобы не проебалась. На этот раз никаких сопливых стишков, а только tips and trics. А конкретно, инициализация коллекции как массива.

You can create and initialize a new collection as an expression by using the "double-brace" syntax:
E.g.
private static final Set VALID_CODES = new HashSet() {{
add("XZ13s");
add("AB21/X");
add("YYLEX");
add("AR2D");
}};

В результате, вместо:
Set validCodes = new HashSet();
validCodes.add("XZ13s");
validCodes.add("AB21/X");
validCodes.add("YYLEX");
validCodes.add("AR2D");
removeProductsWithCodeIn(validCodes);

Остается:
removeProductsWithCodeIn(new HashSet() {{
add("XZ13s");
add("AB21/X");
add("YYLEX");
add("AR5E");
}});

Ня^^
http://www.c2.com/cgi/wiki?DoubleBraceInitialization


Пысы: а еще можно написать метод, который будет создавать нужную коллекцию:
T populateCollection(Collection c, T... things) {
c.addAll(Arrays.asList(things));
return c;
}
Да, еще один совет, позволяющий reduce boilerplate.
http://www.c2.com/cgi/wiki?VarargsCollectionFactoryMethod

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Bolga-777

Франциска Вудворт — «Смешение судеб»

Вторник, 23 Августа 2016 г. 20:19 (ссылка)
litlib.net/bk/60959

Как хочется просто жить и любить, наслаждаясь семейным счастьем. Казалось бы, мы победили в войне, нашли новых друзей и ответы на вопросы, но… Как жаль, что в жизни всегда есть это пресловутое «но». Меня опять втягивают в интриги и вынуждают ходить по лезвию ножа. Хватит ли у меня сил? Смогу ли я? Знаю лишь, что должна, если желаю сохранить свою любовь и мужа.
Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Вы препарируете труп используя SOLID

Понедельник, 22 Августа 2016 г. 12:15 (ссылка)

Как говорится «это безумие, делая снова и снова одно и тоже, ничего при этом не меняя, надеяться на какой-нибудь другой результат»

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

Есть область где подобное действия не только вызывали бы скептицизм, но могут преподносится как единственно верные – объектно-ориентированное программирование.

Начнем мы, как и положено, с самой слабой из парадигм «принципов SOLID», которые хорошо, что в граните не выбиваю.

Приготовитесь много букв…



Дадим краткое определение: SOLID сокр. от англ. single responsibility, open-closed, Liskov substitution, interface segregation и dependency inversion. Т.е. достаточно небольшой набор принципов из всего многообразия, но проводящие четкие границы между тем что можно делать, что лучше не делать, а что надо точно переделывать в Вашем проекте.

Начнем.



Принцип подстановки Барбары Лисков

L, LSP, Liskov substitution principle

«объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы»

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

Для буквоедов
Дословное утверждение звучало примерно как:

Subtype Requirement: Let f(x) be a property provable about objects x of type T. Then f(y) should be true for objects y of type S where S is a subtype of T.


Оперирует не вообще программой, а свойством одного типа. Что конечно меньше, но сути-то не меняет. В ООП множество типов определяют работу программы.



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



Пойдем дальше.

Размер потребляемых ресурсов: памяти, процессорного времени, используемых ядер, необходимость или отсутствие доп. оборудования.

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

Если конечно покопать, то конечно можно уменьшить требования: мол не для всех типов, не для всех свойств, да и не всегда. Но тогда и суть принципа очень размыта. Что-то из разряда «Вы можете переходить только на зелёный свет, но если сломался светофор … или в прямой видимости на расстоянии двух километров не видно машин … или пролетает единорог ^_^''»



Как проектировщики или разработчики Мы уже идем на риск (часто оправданный) нарушая Принцип подстановки Барбары Лисков когда оптимизируем или рефакторим код.

Данный принцип не выполним никогда, простая замена Int32 на Int64 уже делает его не выполнимым. Надеюсь обратная замена Int64 на Int32 не вызывает ни у кого сомнений его нарушения.



Фанатично придерживаясь его, Вы создается что-то уже «мертвое», поскольку оно не «дышит» при рождении и не когда не задышит после. Вы сами с завидным упорством будете отрезать всё «лишнее», чтобы не менять поведения нового. Однажды создав нечто, Вы обречены создавать тоже и в будущем. Поздравляю Вас, Вы создали труп и бережно следите за множеством рук в резинных перчатках.



Принцип открытости/закрытости

O, OCP, Open/closed principle

«программные сущности… должны быть открыты для расширения, но закрыты для модификации»



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



Возможно Вас утешает что можно изменить код: до тестирования, до передачи в продакшен, до выпуска версии, до … (выберите несколько, или подчеркните нужное, или допишите своё). Не важно, у Вас всегда будет это «ДО». Слабое утешение в системах, жизнь которых не исчисляется часами и неделями, а длиться годами.



Вы когда-нибудь наблюдали чтобы в природе, что-то развивается «до»? Не вырастает дерево два метра ровно, всегда чуть выше, чуть ниже. И пока его не срубят будет расти, какая-то ветка засохнет, какая-то разовьётся. Единственно что не достижимо в реальном мире – постоянство.



Зачем далеко ходить: C => C++ => (Java =>) C# и Java => Scala => Kotlin попытки избежать эту проблему, а не решить. Вынужденные придерживаясь это принципа Вы рано или поздно сядете и перепишите всё, если, конечно, к тому времени Ваш проект уже не протух настолько, что его закопали.

Данный принцип ставит окончательный и жирный крест на Вашем проекте в самом его начале.

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



Оставшиеся принципы можно оставить для следующей статьи (если конечно она последует)…



Вывод прозаичен

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



Зачем писать о том, что и так уже было создано и так тщательно скрывается, дезодорируется и препарируется. Когда каждому из участников действия, кому раньше, кому позже, становится ясно что «пора».



?.. Надежда

Но что делать, спросите Вы? (Если конечно дочитали и задумались)

Создание «мутантов» тоже не выход. Если нечто изменяет своё поведение непредсказуемо, без надобности, то обычно оно либо умирает само, либо его удаляют.



Ответ достаточно прост – смотри вокруг, выползите из под груды принципов и методологий.

Прислушивайтесь к советам, но думайте, когда время следовать им, а когда нарушать.

Соблюдайте тот контракт, который нужно, но не более того. В конце концов ни многим интересно что делает ваш код, если он работает корректно и ожидаемо.

Если кто-то обошел вашу «фичу» лучше пусть он удалить этот костыль, ставший не нужным, чем Вы дальше будете с упорством продолжать поддерживать ставшее ошибочным решение.

(Хорошая аналогия с пациентом, не желающим оставить ставшие не нужными костыли после снятия гипса, он же к ним привык. Удобно, а нога болит при ходьбе)



Если кто-то (клиент, менеджер, PM) требует остаться на месте, заведите для него версию и пусть препарирует, помогайте иногда ему (особенно если он платит). Но не стесняйтесь показывать более удачное решение. Дайте человеку шанс изменить решения.



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



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



Не создавайте трупы.

Развивайтесь или умрите.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/308218/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Joker Student Edition: Лучшие видео прошлых конференций

Пятница, 19 Августа 2016 г. 16:52 (ссылка)

Бескрайние просторы интернета часто озаряются вспышками праведного гнева по поводу бессмысленности и бесполезности студентов-айтишников, нашего образования и сетований в стиле «раньше трава была зеленее».







Этот пост получится большим, а все вот почему: мы рассмотрим ТОП-5 докладов с двух наших студенческих конференций (Joker 2015 University Day и JPoint 2016 Student Day), поговорим о том, чего хочет молодежь в 2016 году, а также пройдемся по новому формату Joker 2016 Student Edition (Петербург, 15 октября, Экспофорум).



Чего хотят студенты и начинающие Java-разработчики?



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



Прежде, чем мы начнем рассматривать лучшие доклады, следует кое-что уточнить. Хоть в названиях наших конференций есть слова Student/University, важно отметить, что это профессиональные конференции, по факту рассчитанные на студентов, работающих на позиции Junior’а и ищущих свой путь в Java-мире. Кстати, это наш первый Java-ТОП без Алексея @shipilev Шипилева :)



Итак, давайте посмотрим, какие доклады собрали максимальный отклик среди молодой аудитории:



Виктор gAmUssA Гамов, «Распределяй и властвуй: введение в распределенные системы»

Доклад Senior Solution Architect из компании Hazelcast, которая занимается распределенной обработкой данных (in-memory data grid) с открытым исходным кодом, включивший в себя как общее введение и обзор терминов из области распределенных вычислений, так и конкретные примеры кода и live-демки. Примечательно, что Виктор не стал останавливаться на базовых примерах, но и рассказал о подводных камнях разных подходов к организации распределенных систем.









Mаксим Дорофеев, «Студенческий синдром: почему мы все делаем в последний момент?»

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



В общем, если у вас пока нет 50 минут на просмотр, не рекомендую начинать, потому что оторваться нереально. Оставьте в закладках на вечер.









Josh Long, Pivotal, «The Bootiful Microservice»

Демо-доклад, на котором вы вместе со спикером (одним из лучших в мире live-кодеров), начнете с разработки простого веб-приложения при помощью Spring, а закончите на безопасном мессенджере, собранном за 1 час. Радует, что доклады отлично «заходят» и на английском языке.









Идель Пивницкий, «Что может дать Open Source студенту. Выжимаем максимум удовольствия и пользы»

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

В видео вы найдете обзор программ поддержки начинающих разработчиков от Google, Mozilla, KDE и многих других; инструкцию, как именно начать коммитить в Open-Source; FAQ, почему вы точно подходите для работы с Open Source; подборка инструментов для этого.









Барух jbaruch Садогурский, Кирилл tolkkv Толкачев, «Баттл инструментов для сборки — Maven vs Gradle»

Maven — самый популярный инструмент для сборки Java приложений. Gradle всё быстрее набирает популярность и скоро-скоро затмит лидера. В этом докладе разбираемся, что лучше? Интерактивно, весело, доступно – в таком формате JavaOne Rock-Star Барух Садогурский с Кириллом Толкачевым рассказывают о популярных системах сборки и опасностях, которые они в себе таят.



В этом видео на live-примерах ребята обсуждают не только критерии выбора системы и подходы к сборке. После доклада вы поймете (если до этого не понимали). что вообще такое система сборки, что такое непрерывная интеграция, что и с чем она интегрирует, и как правильно расшифровывается аббревиатура “CD”.









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



Что они получают?



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



В начале статьи мы говорили о том, что Joker 2016 Student Edition – это профессиональная конференция, единственная в своем роде. Здесь студенты за один день смогут получить полный обзор доступных путей в мире Java (правда без Scala, но мы не садисты): от низкоуровневых исследований производительности до новейших тулзов. И здесь со студентами и Junior’ами не будут обращаться как с учениками, здесь они смогут почувствовать себя профессионалами. А это многого стоит.



Что будет на Joker 2016 Student Edition?



Andres Almiray, Canoo Engineering AG – Java libraries you can't afford to miss



Посвященный 20-летию Java обзор наиболее популярных и эффективных Java библиотек и фреймворков от Java Champion с более чем 16-летним опытом в области проектирования и разработки ПО. В докладе поговорим не о тех инструментах, которые должны быть в арсенале каждого разработчика, но и обсудим многообещающие растущие проекты.









Антон Архипов, ZeroTurnaround — Байткод для любознательных



Низкоуровневый доклад для тех, кто хочет научиться говорить с компилятором на его языке от Антона Архипова, Java Champion’а, гуру класслоадинга и модификации байткода. Кстати, совсем недавно брали у него интервью, советую ознакомиться.











Максим Сячин, Luxoft — Микросервисы: первая кровь



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



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



Сергей Владимиров, МФТИ (ГУ)/Сбертех – Оптимизация: не всё то золото…



Думаете, что оптимизация — это ассемблер, борьба за наносекунды и управление GC? Не обольщайтесь, чаще всего в коде есть десятки совершенно несерьезных промахов в области производительности. В докладе приведены примеры оптимизаций реального кода, когда от изменения используемых алгоритмов получали ускорение в 100 и более раз:


  • Pattern matching. Как проверить соответствие строки 1000+ шаблонам за микросекунду;

  • Работа с ORM, скрытые связи и потери, которые выявит даже профайлер бедного человека;

  • Batch. О чём молчат stream'ы.



Владимир Красильщик, Яндекс – Анти-введение в Big Data



Что такое Big Data, как искать и находить эту Big Data в проектах и продуктах? Зачем, как и из чего строятся приложения, основанные на принципах Big Data. Как определить, «большая» у вас data, или маленькая?



В этом докладе поговорим о realtime, пакетной обработке, хранении данных и покемонах.







Andrzej Grzesik, Burberry – Are you aware of /bin of your JDK?

Хардкорный доклад про инструментарий работы, который есть под рукой каждого Java-разработчика: анализ дампов памяти, стек-трейсов и мониторинг работы GC, – все это доступно «из коробки».



В рамках доклада Андрей расскажет, как использовать JDK на полную катушку, сопровождая свои слова live-demo и распространенными примерами.









Кирилл Толкачев и Александр Тарасов, Альфа-Лаборатория – От любви до ненависти — один шаг

Случалось ли, что вы видели (чужой) код и хотели все переписать? Бывало такое, что вы не могли понять, почему кем-то было принято конкретное решение, не другое? Хотели ли вы воскликнуть: «А я бы сделал еще круче!»? Если вы задумывались об этом, вам будет интересно послушать историю о том, как эти вопросы возникали у Александра и Кирилла и как они решались в условиях крупной корпорации.



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



Вместе со слушателями Александр и Кирилл проделают упражнение по созданию «таблицы технологий» и её эволюции. Также они покажут, насколько важно инженерное решение на любой из стадий развития системы.











Дискуссионные зоны и стенды спонсоров.



Как и в большом Joker, на Student Edition будут дискуссионные зоны: одна из ключевых фишек наших конференций 2016 года. Если вкратце – после доклада, спикеры будут еще в течение часа отвечать на вопросы, холиварить, если потребуется и вообще всячески общаться с участниками в свободном формате.



Почти тут же ребята смогут встретиться и поговорить с разработчиками и PM’ами из крупных IT-компаний, таких как Одноклассники, Luxoft, T-Systems, EPAM, JetBrains и многие другие. Важно помнить, что на Joker SE с участниками будут говорить не как со студентами/учениками, а как с начинающими профессионалами, – это, как показывает практика прошлых конференций, многое меняет как в головах студентов, так и в умах работодателей.



Именно для того, чтобы погрузить наших молодых участников в атмосферу «взрослого» Joker, а также дать им возможность пообщаться не только с друзьями-студентами, но и с опытными коллегами (более 80% участников Joker – разработчики уровня Senior/Middle), мы проводим Joker 2016 Student Edition 15 октября, в параллели и на той же площадке, что и «взрослый» Joker 2016.



Шутейная задачка вместо постскриптума: напишите в комментариях, по какому принципу расставлены участницы JPoint Student Day на картинке ниже.




Original source: habrahabr.ru.

https://habrahabr.ru/post/308112/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Плагин CsvLogWriter для JMeter

Пятница, 19 Августа 2016 г. 11:08 (ссылка)

Введение



Наверняка каждый, кто пользовался стандартными листенерами в JMeter, сталкивался со следующими ограничениями:


  • стандартные листенеры не позволяют получить подробную информацию по всем запросам, прописанным в тест плане;

  • стандартные листенеры выводят информацию в XML — формате, что осложняет дальнейший анализ логов средствами Excel и IPython.



Чтобы обойти данные ограничения, было принято решение переработать формирование лог-файлов с помощью нового плагина CsvLogWriter.



Поставленные задачи



Необходимо было разработать плагин для JMeter, который обладал бы следующими функциональными возможностями:


  • вывод полного текста ошибки в строковом формате;

  • фиксация данных по дочерним подзапросам.



В стандартных листенерах для JMeter фиксация полного содержания ошибки возможна в XML-формате, что доставляет неудобства для анализа. Возникла потребность сохранять текст ошибки в строковом формате с последующей записью, например, в CSV-формат для обеспечения возможности построения графиков в Excel и IPython. Обычно получаемые лог-файлы не отображают данные по дочерним подзапросам. Что крайне неудобно при использовании сложной структуры тест-плана. Пример структуры продемонстрирован на рисунке 1.





Рисунок 1. Структура тест-плана



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



Описание функционала плагина pflb@CsvLogWriter



В ходе работы был написан плагин pflb@CsvLogWriter для JMeter. К ключевым особенностям данного плагина можно отнести то, что он может фиксировать результаты работы дочерних подзапросов и записывать полный текст ошибки, при ее возникновении, в виде обычного текста, а не в XML-формате.



Формат лога


Данные, фиксируемые в лог-файле, представлены в таблице 1.

Таблица 1. Формат лога










































































































































































































































































































































Имя Тип Описание Примеры значений для колонки лога Единица измерения
1 timeStamp long Время начала или конца запроса мс
2 elapsed long Длительность обработки запроса: endTime — startTime — idleTime 49, 434 мс
3 label String Наименование компонента JMeter
4 responseCode String Код ответа на запрос «200», «Non HTTP response code: java.net.UnknownHostException»
5 responseMessage String Расшифровка кода ответа «OK», «Internal Server Error»
6 threadName String Имя потока «Thread Group 1-1»
7 dataType String Тип данных в ответе, на практике принимает два значения — «bin» или «text» «bin», «text»
8 success boolean Статус успешности выполнения запроса true или false
9 failureMessage String Сообщение об ошибке,

в случае срабатывания Assertion-компонента,

добавленного к Sampler-у.

В CsvLogWriter в поле записываются сообщения

ото всех Assertion-компонентов,

выполнение которых сгенерировало ошибку.

В базовом логере записывается только первое сообщение.
10 bytes int Размер ответа.

Значение и алгоритм расчёта зависят от настроек

sampler-а. На значение могут влиять responseData.length,

headersSize, bodySize.
Байт
11 grpThreads int Количество активных потоков в текущей группе
12 allThreads int Количество активных виртуальных пользователей всех групп
13 URL String Ссылка
14 Filename String Наименования файла, в который записываются ответы.

Поле заполняется при использовании Save Response to File Listener.

Этот Listener редко используется, обычно значение колонки

— пустая строка
15 Latency int Время до получения первого ответа сервера.

Эта временная задержка включает в себя время,

потраченное на соединение с сервером,

задержки, обусловленные установкой защищённого соединения,

и внутренними задержками JMeter на получение

первых байт ответа сервера. Если по какой-то причине

работа Sampler-а была приостановлена, а потом возобновлена,

то значение Latency будет скорректировано

на длительность приостановки Sampler-а.
мс
16 Encoding String Кодировка. Возвращается кодировка ответа,

если кодировка ответа не задана,

то возвращается значение кодировки по умолчанию.

Значение кодировки по умолчанию задано в

«sampleresult.default.encoding».

Для HTTP Request значение по умолчанию «ISO-8859-1».
«ISO-8859-1», «UTF-8»
17 SampleCount int Количество семплов.

Для HTTP Request значение равно 1.

Для JMS Sampler, выполняющего подписку на события

и чтение нескольких сообщений за раз,

значение равно количеству циклов опроса

или количеству прочитанных сообщений.

Значение всегда больше или равно одному.
1, 2 шт
18 ErrorCount int Количество ошибок.

Для HTTP Request значение равно 0 если success

и равно 1 если запрос не успешный.

Для других sampler-ов выполняющих обработку

нескольких сообщений за раз,

значение может быть больше 1.
0, 1 шт
19 Hostname String Наименование машины
20 IdleTime int Время простоя мс
21 Connect int Время, затраченное на установку соединения мс
22 headersSize int Размер заголовков Байт
23 bodySize int Размера тела Байт
24 contentType String Тип содержимого из заголовка ответа
25 endTime long Время конца запроса мс
26 isMonitor boolean Признак поставлена ли галочка Use as Monitor true, false
27 threadName_label String Наименование треда и компонента JMeter
28 parent_threadName_label String Наименование треда и компонента JMeter родителя
29 startTime long Время начала запроса мс
30 stopTest boolean Признак остановлен ли тест — кнопка Stop.

Также в настройках Thread Group есть опция

«Stop Test» при ошибке. Если в колонке «stopTest»

стоит true, значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
31 stopTestNow boolean Признак остановлен ли тест резко — кнопка Shutdown.

Также в настройках Thread Group есть опция

«Stop Test Now» при ошибке. Если в колонке «stopTestNow»

стоит true, значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
32 stopThread boolean Признак остановлен ли текущий поток.

В настройках Thread Group есть опция «Stop Thread»

при ошибке. Если в колонке «stopThread» стоит true,

значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
33 startNextThreadLoop boolean Стартует ли повтор.

В настройках Thread Group есть опция «Start Next Thread Loop»

при ошибке. Если в колонке «startNextThreadLoop» стоит true,

значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
34 isTransactionSampleEvent boolean Признак того, что текущее событие является транзакцией (TransactionController). То есть, это лишь группирующий элемент. true, false
35 transactionLevel int Уровень вложенности запроса.

Если используется иерархия Transaction Controller

или у подзапросов есть подзапросы,

то в данной колонке будет уровень вложенности.
0 для корневого запроса или корневого Transaction Controller.

1 для подзапроса, родитель которого является корневым.
36 responseDataAsString String Полное содержание ошибки в формате строки

в случае ее возникновения, если success == false,

то в responseData будет содержаться полное тело ответа
37 requestHeaders String Заголовки запроса
38 responseData String Полное содержание ошибки в случае ее возникновения,

если success == false, то в responseData будет содержаться

полное тело ответа, перекодированное в base64
39 responseHeaders String Заголовки ответа
40 <Имя переменной> String Переменные JMeter


Структура лога расширяет базовый формат CSV лога. С базовым набором параметров можно ознакомиться по ссылке jmeter.apache.org/usermanual/listeners.html#csvlogformat



Полученный CSV-лог можно загрузить любым базовым Listener-ом JMeter, поддерживающим загрузку CSV-лога.

Также в логе появились дополнительные колонки, которые могут пригодится при анализе (стр. 22-35 таблицы Формат лога).

Тела и заголовки ответов и запросов записываются только при ошибках (стр. 36-39 таблицы Формат лога).

Также в лог запишутся колонки для переменных: jmeter.apache.org/usermanual/listeners.html#sample_variables — описание возможности логировать значения переменных.



Интерфейс



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



Так же на форме расположены флажки. С помощью флажков можно манипулировать данными, фиксируемыми в логе. Флажок Additional parameters отвечает за фиксацию дополнительных параметров (22-35 строки в таблице Формат лога), Response data отвечает за фиксацию текста ошибок (36-39 строки в таблице Формат лога), User variables отвечает за фиксацию пользовательских переменных.



Интерфейс плагина представлен на рисунке 2.





Рисунок 2. Интерфейс плагина CSVLogWriter



Сравнение плагина CSVLogWriter и Simple Data Writer



В данном разделе попробуем провести сравнение плагина CsvLogWriter и стандартного листенера Simple Data Writer.



Состав логируемых данных


Листенер Simple Data Writer дает пользователю возможность настроить список фиксируемых данных. На рисунке 3 показано окно настроек выводимых данных.





Рисунок 3. Окно настроек фиксируемых данных листенера Simple Data Writer



Плагин CsvLogWriter всегда выводит базовый перечень параметров (аналогичный Simple Data Writer) и позволяет настроить вывод списка дополнительных данных с помощью 3 флажков на форме:


  • Additional parameters — дополнительные параметры (22-35 строки в таблице Формат лога);

  • Response data — тексты ошибок (36-39 строки в таблице Формат лога);

  • User variables — пользовательские переменные (для вывода необходимо запускать JMeter с ключом -Jsample_variables).



Детальный перечень фиксируемых данных жестко прописан в коде. Но, как видно на рисунке 3, Simple Data Writer не может выводить текст ошибки в строковом формате. Полный текст ошибки фиксируется только в XML формате. По этой причине в случае, когда нам необходим текст ошибок приходится вести 2 лога — 1 в CSV-формате (если необходима дальнейшая обработка лога с построением графиков в Excel или iPython) и 1 в XML-формате.



Логирование подзапросов


Так же, листенер Simple Data Writer не фиксирует результаты работы дочерних подзапросов, соответственно, такой лог-файл нельзя назвать исчерпывающим. Для наглядного сравнения объема выводимых данных запустим тест, соответствующий тест-плану на рисунке 1, и посмотрим на лог-файлы. Лог-файл SimpleDataWriter представлен на рисунке 4.





Рисунок 4. Лог-файл Simple Data Writer



Как видно на рисунке 4, SimpleDataWriter выводит информацию только по Transaction Controller1. В свою очередь, плагин CsvLogWriter за счет обработки дочерних подзапросов выводит гораздо больше информации. Содержание лог-файла плагина CsvLogWriter представлено на рисунке 5.





Рисунок 5. Лог-файл CsvLogWriter



Сравнение быстродействия



Так же проводился анализ быстродействия метода SimpleOccured, отвечающего за обработку событий. Профилирование велось в Java VisualVM. В тест плане не использовались подзапросы. Для SimpleDataWriter тестирование запускалось с записью в 1 CSV-файл и с записью в 2 файла — CSV и XML. Количество виртуальных пользователей составляло 10, количество повторение 100. Итоги сравнения приведены в таблице 2.



Таблица 2. Сравнение быстродействия SimpleDataWriter и плагина CsvLogWriter

















CsvLogWriter SimpleDataWriter (CSV+XML) SimpleDataWriter (CSV)
Длительность (мс), количество вызовов Длительность (мс), количество вызовов Длительность (мс), количество вызовов
215, 2000 23076, 4000 101, 2000


Выводы:


  • CsvLogWriter в 10 раз быстрее SimpleDataWriter (XML с максимальной детализацией);

  • CsvLogWriter в 2 раза медленнее SimpleDataWriter (CSV с максимальной детализацией);

  • SimpleDataWriter (XML с максимальной детализацией) в 20 раз медленнее SimpleDataWriter (CSV с максимальной детализацией).





Ссылка на плагин



github.com/pflb/Jmeter.Plugin.CsvLogWriter
Original source: habrahabr.ru.

https://habrahabr.ru/post/308098/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Плагин CsvLogWriter для JMeter

Пятница, 19 Августа 2016 г. 11:08 (ссылка)

Введение



Наверняка каждый, кто пользовался стандартными листенерами в JMeter, сталкивался со следующими ограничениями:


  • стандартные листенеры не позволяют получить подробную информацию по всем запросам, прописанным в тест плане;

  • стандартные листенеры выводят информацию в XML — формате, что осложняет дальнейший анализ логов средствами Excel и IPython.



Чтобы обойти данные ограничения, было принято решение переработать формирование лог-файлов с помощью нового плагина CsvLogWriter.



Поставленные задачи



Необходимо было разработать плагин для JMeter, который обладал бы следующими функциональными возможностями:


  • вывод полного текста ошибки в строковом формате;

  • фиксация данных по дочерним подзапросам.



В стандартных листенерах для JMeter фиксация полного содержания ошибки возможна в XML-формате, что доставляет неудобства для анализа. Возникла потребность сохранять текст ошибки в строковом формате с последующей записью, например, в CSV-формат для обеспечения возможности построения графиков в Excel и IPython. Обычно получаемые лог-файлы не отображают данные по дочерним подзапросам. Что крайне неудобно при использовании сложной структуры тест-плана. Пример структуры продемонстрирован на рисунке 1.





Рисунок 1. Структура тест-плана



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



Описание функционала плагина pflb@CsvLogWriter



В ходе работы был написан плагин pflb@CsvLogWriter для JMeter. К ключевым особенностям данного плагина можно отнести то, что он может фиксировать результаты работы дочерних подзапросов и записывать полный текст ошибки, при ее возникновении, в виде обычного текста, а не в XML-формате.



Формат лога


Данные, фиксируемые в лог-файле, представлены в таблице 1.

Таблица 1. Формат лога










































































































































































































































































































































Имя Тип Описание Примеры значений для колонки лога Единица измерения
1 timeStamp long Время начала или конца запроса мс
2 elapsed long Длительность обработки запроса: endTime — startTime — idleTime 49, 434 мс
3 label String Наименование компонента JMeter
4 responseCode String Код ответа на запрос «200», «Non HTTP response code: java.net.UnknownHostException»
5 responseMessage String Расшифровка кода ответа «OK», «Internal Server Error»
6 threadName String Имя потока «Thread Group 1-1»
7 dataType String Тип данных в ответе, на практике принимает два значения — «bin» или «text» «bin», «text»
8 success boolean Статус успешности выполнения запроса true или false
9 failureMessage String Сообщение об ошибке,

в случае срабатывания Assertion-компонента,

добавленного к Sampler-у.

В CsvLogWriter в поле записываются сообщения

ото всех Assertion-компонентов,

выполнение которых сгенерировало ошибку.

В базовом логере записывается только первое сообщение.
10 bytes int Размер ответа.

Значение и алгоритм расчёта зависят от настроек

sampler-а. На значение могут влиять responseData.length,

headersSize, bodySize.
Байт
11 grpThreads int Количество активных потоков в текущей группе
12 allThreads int Количество активных виртуальных пользователей всех групп
13 URL String Ссылка
14 Filename String Наименования файла, в который записываются ответы.

Поле заполняется при использовании Save Response to File Listener.

Этот Listener редко используется, обычно значение колонки

— пустая строка
15 Latency int Время до получения первого ответа сервера.

Эта временная задержка включает в себя время,

потраченное на соединение с сервером,

задержки, обусловленные установкой защищённого соединения,

и внутренними задержками JMeter на получение

первых байт ответа сервера. Если по какой-то причине

работа Sampler-а была приостановлена, а потом возобновлена,

то значение Latency будет скорректировано

на длительность приостановки Sampler-а.
мс
16 Encoding String Кодировка. Возвращается кодировка ответа,

если кодировка ответа не задана,

то возвращается значение кодировки по умолчанию.

Значение кодировки по умолчанию задано в

«sampleresult.default.encoding».

Для HTTP Request значение по умолчанию «ISO-8859-1».
«ISO-8859-1», «UTF-8»
17 SampleCount int Количество семплов.

Для HTTP Request значение равно 1.

Для JMS Sampler, выполняющего подписку на события

и чтение нескольких сообщений за раз,

значение равно количеству циклов опроса

или количеству прочитанных сообщений.

Значение всегда больше или равно одному.
1, 2 шт
18 ErrorCount int Количество ошибок.

Для HTTP Request значение равно 0 если success

и равно 1 если запрос не успешный.

Для других sampler-ов выполняющих обработку

нескольких сообщений за раз,

значение может быть больше 1.
0, 1 шт
19 Hostname String Наименование машины
20 IdleTime int Время простоя мс
21 Connect int Время, затраченное на установку соединения мс
22 headersSize int Размер заголовков Байт
23 bodySize int Размера тела Байт
24 contentType String Тип содержимого из заголовка ответа
25 endTime long Время конца запроса мс
26 isMonitor boolean Признак поставлена ли галочка Use as Monitor true, false
27 threadName_label String Наименование треда и компонента JMeter
28 parent_threadName_label String Наименование треда и компонента JMeter родителя
29 startTime long Время начала запроса мс
30 stopTest boolean Признак остановлен ли тест — кнопка Stop.

Также в настройках Thread Group есть опция

«Stop Test» при ошибке. Если в колонке «stopTest»

стоит true, значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
31 stopTestNow boolean Признак остановлен ли тест резко — кнопка Shutdown.

Также в настройках Thread Group есть опция

«Stop Test Now» при ошибке. Если в колонке «stopTestNow»

стоит true, значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
32 stopThread boolean Признак остановлен ли текущий поток.

В настройках Thread Group есть опция «Stop Thread»

при ошибке. Если в колонке «stopThread» стоит true,

значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
33 startNextThreadLoop boolean Стартует ли повтор.

В настройках Thread Group есть опция «Start Next Thread Loop»

при ошибке. Если в колонке «startNextThreadLoop» стоит true,

значит произошла именно такая ситуация.

Сценарий прервался на текущем запросе.
true, false
34 isTransactionSampleEvent boolean Признак того, что текущее событие является транзакцией (TransactionController). То есть, это лишь группирующий элемент. true, false
35 transactionLevel int Уровень вложенности запроса.

Если используется иерархия Transaction Controller

или у подзапросов есть подзапросы,

то в данной колонке будет уровень вложенности.
0 для корневого запроса или корневого Transaction Controller.

1 для подзапроса, родитель которого является корневым.
36 responseDataAsString String Полное содержание ошибки в формате строки

в случае ее возникновения, если success == false,

то в responseData будет содержаться полное тело ответа
37 requestHeaders String Заголовки запроса
38 responseData String Полное содержание ошибки в случае ее возникновения,

если success == false, то в responseData будет содержаться

полное тело ответа, перекодированное в base64
39 responseHeaders String Заголовки ответа
40 <Имя переменной> String Переменные JMeter


Структура лога расширяет базовый формат CSV лога. С базовым набором параметров можно ознакомиться по ссылке jmeter.apache.org/usermanual/listeners.html#csvlogformat



Полученный CSV-лог можно загрузить любым базовым Listener-ом JMeter, поддерживающим загрузку CSV-лога.

Также в логе появились дополнительные колонки, которые могут пригодится при анализе (стр. 22-35 таблицы Формат лога).

Тела и заголовки ответов и запросов записываются только при ошибках (стр. 36-39 таблицы Формат лога).

Также в лог запишутся колонки для переменных: jmeter.apache.org/usermanual/listeners.html#sample_variables — описание возможности логировать значения переменных.



Интерфейс



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



Так же на форме расположены флажки. С помощью флажков можно манипулировать данными, фиксируемыми в логе. Флажок Additional parameters отвечает за фиксацию дополнительных параметров (22-35 строки в таблице Формат лога), Response data отвечает за фиксацию текста ошибок (36-39 строки в таблице Формат лога), User variables отвечает за фиксацию пользовательских переменных.



Интерфейс плагина представлен на рисунке 2.





Рисунок 2. Интерфейс плагина CSVLogWriter



Сравнение плагина CSVLogWriter и Simple Data Writer



В данном разделе попробуем провести сравнение плагина CsvLogWriter и стандартного листенера Simple Data Writer.



Состав логируемых данных


Листенер Simple Data Writer дает пользователю возможность настроить список фиксируемых данных. На рисунке 3 показано окно настроек выводимых данных.





Рисунок 3. Окно настроек фиксируемых данных листенера Simple Data Writer



Плагин CsvLogWriter всегда выводит базовый перечень параметров (аналогичный Simple Data Writer) и позволяет настроить вывод списка дополнительных данных с помощью 3 флажков на форме:


  • Additional parameters — дополнительные параметры (22-35 строки в таблице Формат лога);

  • Response data — тексты ошибок (36-39 строки в таблице Формат лога);

  • User variables — пользовательские переменные (для вывода необходимо запускать JMeter с ключом -Jsample_variables).



Детальный перечень фиксируемых данных жестко прописан в коде. Но, как видно на рисунке 3, Simple Data Writer не может выводить текст ошибки в строковом формате. Полный текст ошибки фиксируется только в XML формате. По этой причине в случае, когда нам необходим текст ошибок приходится вести 2 лога — 1 в CSV-формате (если необходима дальнейшая обработка лога с построением графиков в Excel или iPython) и 1 в XML-формате.



Логирование подзапросов


Так же, листенер Simple Data Writer не фиксирует результаты работы дочерних подзапросов, соответственно, такой лог-файл нельзя назвать исчерпывающим. Для наглядного сравнения объема выводимых данных запустим тест, соответствующий тест-плану на рисунке 1, и посмотрим на лог-файлы. Лог-файл SimpleDataWriter представлен на рисунке 4.





Рисунок 4. Лог-файл Simple Data Writer



Как видно на рисунке 4, SimpleDataWriter выводит информацию только по Transaction Controller1. В свою очередь, плагин CsvLogWriter за счет обработки дочерних подзапросов выводит гораздо больше информации. Содержание лог-файла плагина CsvLogWriter представлено на рисунке 5.





Рисунок 5. Лог-файл CsvLogWriter



Сравнение быстродействия



Так же проводился анализ быстродействия метода SimpleOccured, отвечающего за обработку событий. Профилирование велось в Java VisualVM. В тест плане не использовались подзапросы. Для SimpleDataWriter тестирование запускалось с записью в 1 CSV-файл и с записью в 2 файла — CSV и XML. Количество виртуальных пользователей составляло 10, количество повторение 100. Итоги сравнения приведены в таблице 2.



Таблица 2. Сравнение быстродействия SimpleDataWriter и плагина CsvLogWriter

















CsvLogWriter SimpleDataWriter (CSV+XML) SimpleDataWriter (CSV)
Длительность (мс), количество вызовов Длительность (мс), количество вызовов Длительность (мс), количество вызовов
215, 2000 23076, 4000 101, 2000


Выводы:


  • CsvLogWriter в 10 раз быстрее SimpleDataWriter (XML с максимальной детализацией);

  • CsvLogWriter в 2 раза медленнее SimpleDataWriter (CSV с максимальной детализацией);

  • SimpleDataWriter (XML с максимальной детализацией) в 20 раз медленнее SimpleDataWriter (CSV с максимальной детализацией).





Ссылка на плагин



github.com/pflb/Jmeter.Plugin.CsvLogWriter
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/308098/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Java Stream API: что делает хорошо, а что не очень?

Среда, 17 Августа 2016 г. 16:02 (ссылка)





Настолько ли «энергичен» Java 8 Stream API? Возможно ли «превращение» обработки сложных операций над коллекциями в простой и понятный код? Где та выгода от параллельных операций, и когда стоит остановиться? Это одни из многочисленных вопросов, встречающихся читателям. Попробуем разобрать подводные камни Stream API с Тагиром Валеевым aka @lany. Многие читатели уже знакомы с нашим собеседником по статьям, исследованиям в области Java, выразительным докладам на конференциях. Итак, без проволочек, начинаем обсуждение.



Тагир, у вас отличные показатели на ресурсе StackOverflow (gold status в ветке «java-stream»). Как вы думаете, динамика применения Java 8 Stream API и сложность конструкций выросла (на основе вопросов и ответов на данном ресурсе)?



— Верно, одно время я много времени проводил на StackOverflow, постоянно отслеживая вопросы по Stream API. Сейчас заглядываю периодически, так как, на мой взгляд, на большинство интересных вопросов уже есть ответы. Безусловно, чувствуется, что люди распробовали Stream API, было бы странно, если бы это было не так. Первые вопросы по этой теме появились ещё до выпуска Java-8, когда люди экспериментировали с ранними сборками. Расцвет пришёлся на конец 2014 и 2015-й год.



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



Вы упомянули про StreamEx. Расскажите, что побудило вас к созданию? Какие цели вы преследовали?



— Мотивы были сугубо практические. Когда на работе мы перешли на Java 8, первая эйфория от красоты и удобства довольно быстро сменилась чередой спотыканий: хотелось сделать с помощью Stream API определённые вещи, которые вроде делаться должны, но по факту не получались. Приходилось удлинять код или отступать от спецификации. Я начал добавлять в рабочие проекты вспомогательные классы и методы для решения данных проблем, но выглядело это некрасиво. Потом я догадался обернуть стандартные стримы в свои классы, которые предлагают ряд дополнительных операций, и работать стало существенно приятнее. Эти классы я выделил в отдельный открытый проект и начал развивать его.



На ваш взгляд, какие виды расчетов и операций и над какими данными действительно стоит реализовать c использованием Stream API, а что не очень подходит для обработки?



— Stream API любит неизменяемые данные. Если вы хотите поменять существующие структуры данных, а не создать новые, вам нужно что-то другое. Посмотрите в сторону новых стандартных методов (например, List.replaceAll).



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



Stream API любит решать одну задачу за проход. Если вы хотите в один обход данных решить несколько разных задач, готовьтесь писать свои коллекторы. И не факт, что это вообще получится.



Stream API не любит проверяемые исключения. Вам будет не очень удобно кидать их из операций Stream API. Опять же есть библиотеки, которые пытаются это облегчить (скажем, jOO

https://habrahabr.ru/post/307938/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<java - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda