Java не відстій - ви просто неправильно його використовуєте

Я будував Java веб-додатки для підприємств, з тих пір як були створені сервлети. У той час екосистема Java сильно змінилася, але, на жаль, багато розробників Java для підприємств, застрягли на деяких дуже хворобливих і неефективних способах ведення справ. У моїх подорожах я продовжую бачити Java відстійні зони - але це не повинно бути так. Це час для підприємств піти від відстійних зон, які вони використовують у платформі Java. Ось список з найбільш осталость частин Java, які я часто помічаю і деякі рекомендації про те, як їх уникати.

10 сторінок Wikis для настройки Dev середовища відстій

Налаштування нової середовища розробки не повинна бути більше 3 кроків:

1. Встановіть JDK

2. Клонувати / перевірити SCM repo

3. Запустити настройку / початок додатки

Жарти в сторону. Воно і повинно бути так легко. Сучасні інструменти для збірки, такі як Gradle і SBT мають пускові, які ви можете вставити прямо в кореневу вихідного дерева, так що нові розробники можуть просто запустити ./gradlew or./activator (для sbt). Збірка повинна мати все необхідне, щоб підняти і запустити додаток - в тому числі сервер. Найпростіший спосіб зробити це, щоб зробити бесконтейнерную обробку з такими речами, як Play Framework і Drop Wizard , але якщо ви застрягли в контейнері, то вам потрібно веб-додаток Webapp Runner . Одна з багатьох проблем з контейнерним підходом - це дуже висока ймовірність отримання синдрому «це працює тільки на моїй машині», тому що середовища легко розрізняються, коли критична залежність існує поза області збірки і SCM. Скільки вики зберігає зміни server.xml оновленими? Конфігурація на базі вікі-це відмінний спосіб заподіяти біль.

Щодо залежностей послуг, таких як бази даних і зовнішніх веб-служб - чи повинні розробники встановлювати ці речі і налаштовувати їх? Ні, якщо ваша збірка може зробити це за них. Розумні системи збирання повинні бути в змозі зберігати необхідні послуги або локально, або на хмарі. Докер виник як відмінний спосіб керувати місцевими середовищами, які є точною копією виробничої системи.

Якщо ваш додаток потребує реляційної базі даних, то використовуйте db в пам'яті, як hsql або хмарні послуги, такі як Heroku Postgres , RDS , Redis Labs , і т.д. Однак ризик з більшістю баз даних в пам'яті в тому, що вони відрізняються від того, що використовується у виробництві. JPA / Hibernate намагаються приховати це, але іноді помилки виникають через тонких відмінностей. Так що краще імітувати виробничі послуги для розробників аж до версії бази даних. Бази даних на основі Java, такі як Neo4J, працюють так само, в пам'яті і поза процесом мінімізації ризиків, а також робить простіше установку нових середовищ розвитку. Зовнішні веб-служби повинні мати або безліч варіантів середовища, які можуть бути використані розробниками або веб-послуги повинні бути зведені нанівець.

Неконгруентность середовища розгортання відстій

Щоб звести до мінімуму ризик при просуванні від розробки до виробництва, єдине, що має змінитися між кожної середовищем - це конфігурація. Розгортається артефакт не повинен змінюватися, коли він рухається між середовищами. Безперервні системи інтеграції повинні запускати ті ж збірки і випробування, з якими працюють розробники. Чи робить система CI автоматичне розгортання на випробувальній або проміжної середовищі. Правильний реліз конвеєрної обробки спрощує просування розгортається артефакту від постановки до виробництва.

Я зазвичай підтримував веб-додаток на Java, де процес розгортання був такий:

1. Створити WAR файл

2. SCP WAR файл на сервер

3. SSH на сервер

4. Витягти WAR файл

5. Змінити web.xml файл, щоб в ньому містилася інформація про з'єднання нової бази даних

6. Запустити сервер

Це установка не найгірша з тих, що я бачив, але завжди була ризикована. Було б набагато краще використовувати змінні середовища, так що єдине, що змінилося між середовищами, це змінні. Змінні середовища можуть бути автоматично зчитуватися додатком, так що артефакт залишається точно таким же. У цьому відтворенні установки п'ятниця - супер легка - просто встановити змінні середовища.

Сервери, яким потрібно більше ніж 30 секунд для запуску - відстій

Для продуктивності розробника так, щоб розширення масштабів могло відбутися миттєво, сервери повинні запускатися швидко. Якщо вашого сервера потрібно більш ніж 30 секунд для старту, тоді розірвіть додаток на більш дрібні шматки, прийнявши архітектуру Microservices . Безконтейнерною або правило однієї програми-на-контейнер може реально допомогти зменшити час запуску. Якщо ваш контейнер займає багато часу для запуску, ви повинні запитати себе: що де там за контейнерні послуги? Чи можуть сервіси бути розбиті на окремі додатки? Чи можуть вони бути видалені або вимкнені?

Якщо вам потрібно озброєння, щоб довести своєму керівництву, що ваш час запуску вбиває продуктивність вашої команди, то використовуйте секундомір на телефоні, щоб підрахувати загальну кількість хвилин в день даремно, чекаючи додаток запуститися. Бонусні бали, якщо ви розрахуєте, скільки даремно грошей витрачено на вас, на вашу команду, і ваш орг. Подвійний бонус очок, якщо ви покажете графік поразок "ми витратили багато грошей на цей сервер додатків" аргумент понесених витрат.

Керовані вручну залежності відстій

Це відстій, якщо будь-яка з ваших бібліотечних залежностей не керується за допомогою інструменту збірки. Вручну копіювання файлів Jar в WEB-INF / lib жахливо помилково. Це ускладнює співвідношення файлів з версіями. Перехідні залежності адресовані ClassNotFound помилками. Залежності є крихкими. Знати ліцензії бібліотек важко. Витягування джерел за допомогою IDE і JavaDocs для бібліотек - жорстко.

Отже, спочатку ... Використовуйте інструмент збірки. Не має значення вибрати вам Ant + Ivy, Maven, Gradle або sbt. Просто виберіть один і використовуйте його для автоматичного витягування залежності від Maven Maven або власного сервера Artifactory / Nexus. З WebJars ви навіть можете керувати Вашою бібліотекою залежностей JavaScript і CSS. Потім автоматично відмовтеся від SCM перевірок, які включають файли Jar.

Неверсірованние & Неопубліковані Бібліотеки відстій

Підприємства, як правило, мають багато бібліотек і послуг спільно з додатків і командам. Щоб зробити команди більш продуктивними і для управління залежностями ці бібліотеки повинні бути версіями і публікувати їх на внутрішні сервери артефактів, таких як Nexus і Artifactory. SNAPSHOT релізів слід уникати, оскільки вони порушують гарантії відтворюється збірки. Замість цього, розгляньте версії на основі вашої інформації SCM. Наприклад, sbt-git плагін за замовчуванням має збірку версії для git хеш або якщо є git тег для поточної позиції, то тег використовується замість цього. Це робить опубліковані релізи непорушними, так що споживачі бібліотек точно знають кореляцію між версією вони використовують і точки-в-часу в коді.

Довга розробка / цикли валідації насправді відстій

Мільярди доларів на рік, ймовірно, витрачені на розробників тільки щоб побачити / перевірити зміни. Сучасні веб-системи, як Play Framework і інструменти, такі як JRebel можуть значно скоротити час на перевірку змін. Якщо кожна зміна вимагає відновлення файлу WAR або перезапуску контейнера, то ви витрачаєте смішні суми грошей. Точно так же, виконання тестів повинно відбуватися безперервно. Тестування зміни коду (через перезавантаження браузера або запуску тесту), не повинно займати багато часу, більше ніж на додаткову компіляцію. Веб системи, які відображають корисні компіляції і виконання помилки в браузері після поновлення також дуже корисні для зменшення довгих циклів ручного тестування.

Коли я працюю з ігровими додатками, я постійно відновлюю джерело на файл, повторно запускаю тести, і перезавантажувати веб-сторінки - все автоматично. Якщо ваші кошти розробки та структури не підтримують цей вид процесу, то прийшов час, щоб це все модернізувати. Я використовував багато структур Java протягом багатьох років і Play Framework безумовно підтримує найостанніший і швидкий цикл змін. Але якщо ви не можете переключитися на Play, JRebel з безперервним плагіном тестування для Maven або Gradle теж хороший.

Монолітні релізи відстій

Якщо ви працюєте в НАСА, то мати цикли випуску довше, ніж два тижні не резонно. Цілком ймовірно, що причина, що у вас такі довгі цикли релізу тому, що десь менеджер намагається зменшити ризик. Цей менеджер, ймовірно, звик до водоспадів, а потім перейшов на Agile, але ніколи більше нічого не міняв. Так у вас є короткі спринти, але код не досягає виробництва протягом декількох місяців, тому що це було б занадто ризиковано випускати частіше. Правда в тому, що безперервна подача (CD) насправді знижує сукупний ризик-релізів. Незалежно від того, як часто ви випускаєте, речі іноді ламаються. Але з малими і більш частими релізами, що фіксують поломку, набагато простіше. При монолітному релізі йде на південь, проходить ваш уїк-енд, тиждень, або іноді місяць. Крім того ... При релізах з'являється гарне почуття. Чому б не робити це весь час?

Перехід на постійну подачу має багато деталей і може зайняти роки, щоб повністю себе охопити (якщо, як і всі стартапи сьогодні, ви не почали з CD). Ось деякі з найбільш важливих елементів про на компакт-диск, який можна швидко реалізувати:

  • Спрощене забезпечення та розгортання додатків: Кожен розробник повинен мати можливість миттєво забезпечити і розгорнути новий додаток.
  • Мікросервіси: логічно групувати послуги / додатки в незалежних розгортання. Легше для команди, щоб рухатися вперед у своєму власному темпі.
  • Роллбекі: Відкат до попередньої версії програми також просто, як гортати перемикач. Існує очевидна сторона розгортання для цього, але є також деякі політики, як правило, потрібно йти на місце навколо зміни схеми.
  • Розв'язані схеми і зміни коду: Коли зміни схеми і коду залежать один від одного, відкати дійсно важкі. Розв'язка обох ізолює ризик і дозволяє повернутися до попередньої версії додатка без з'ясування, що потрібно зробити в той же час зміни схеми.
  • Незмінні Розгортання: Знання кореляції між розгортанням і точним місцем-по-часу в СКМ важливо для усунення неполадок. Якщо ви SSH на сервер, і щось змінити на розгорнутій системі, ви значно знизите вашу здатність до репродукції і зрозумієте проблему.
  • Розгортання нульового втручання: Середовище, в яку ви розгортаєте, повинна володіти конфігурацією програми. Якщо вам потрібно редагувати файли або виконувати інші дії вручну після розгортання, то ваш процес крихкий. Розгортання не повинно бути більше, ніж копіювання випробуваного артефакту до сервера і початок процесу.
  • Автоматичне розгортання: Забезпечення віртуальних серверів, додавання & видалити сервери за балансуванням, авто-запуск серверних процесів і перезапуск мертвих процесів повинні бути автоматизовані.
  • Одноразові Сервери: Не дозволяйте викликати Chaos Monkey . Сервери вмирають. Підготуйтеся до цього, маючи без статусну архітектуру і ефемерні диски. Забезпечте постійне зовнішнє, стійке сховище даних.
  • Центральний Сервіс Входу: Не використовуйте локальний диск для журналів, тому що це запобігає одноразовость і ускладнює пошук по декількох серверах.

• Моніторинг та повідомлення: Налаштуйте автоматизовані здорові перевірки, моніторинг продуктивності і моніторинг логгов. Дізнавайтеся раніше ваших користувачів, коли щось йде не так.

Є тонни деталей до цього всього, в які я не буду вдаватися. Якщо ви хотіли б дізнатися про щось докладніше в наступних постах, напишіть мені в коментарях.

Липкі сесії і стан сервера відстій

Липкі сесії і стан сервера зазвичай одні з кращих способів убити вашу продуктивність і стійкість. Стан сесії (в традиційному сенсі Сервлет) ускладнює постійну подачу і масштабує по горизонталі. Якщо ви хочете, щоб кеш сесії використовував реальну систему кеш - то, що була розроблена, щоб мати справу з використанням мульти-вузла і невдачі. наприклад Memcache, ehcache і т.д. У пам'яті кеш швидко, але важко оголосити недійсним в многоузловой середовищі і не довговічний в перезапуску - він має своє місце, як розрахункове / отримане властивість, де недійсність і перерахунок - це легко.

Веб-додатки повинні рухатися незмінними до кінця. Інтерфейс, пов'язаний зі статусом, повинен жити на клієнті (наприклад, cookies, локальне зберігання, а внутрішня пам'ять) і в зовнішніх сховищах даних (наприклад, баз даних SQL / NoSQL, Memcached сховища і поширені кеш кластери). Зберігайте ці REST послуги 100% без статусу, або статус - монстр буквально з'їсть вас уві сні.

Марне блокування відстій

У традиційному веб-додатку запит приходить, отримує деякі дані з бази даних, створює веб-сторінку, а потім повертає її. У цій моделі було нормально повний трансфер одного потоку, який залишався заблокованим протягом всього терміну запиту. У сучасному світі часто запити залишаються відкритими за життя одного виклику бази даних, тому що, або він є поштовхом з'єднання або він з'єднує кілька фонових служб разом. Цей новий світ вимагає іншу модель для управління темами / блокуванням. Сучасна модель для цього називається асинхронної і без блокування або Reactive .

Більшість традиційних мережевих бібліотек Java (сервлети, JDBC, Apache HTTP і т.д.) блокують. Таким чином, навіть якщо з'єднання простоює (наприклад, коли з'єднання з базою даних чекає запит, щоб повернутися), потік як і раніше виділяється. Модель блокування обмежує паралелізм, горизонтальну масштабованість, а число одночасних підключень. Реактивна модель використовує тільки потоки, коли вони активні. В ідеалі ваше додаток Реактивно весь шлях вниз до базової мережі подій. Коли приходить запит, приходить потік, а потім, якщо запит повинен отримати дані з іншої системи, потік, що обробляє запит, може бути повернутий в пул при очікуванні даних. Після того як дані прибутку, потік може бути виділений на запит, так що відповідь може бути повернутий запитувачу.

Java має великий фундамент для Reactive з Java NIO. Але, на жаль, більшість традиційних фреймворків Java, драйверів баз даних, і HTTP клієнтів, не використовують його. На щастя, є цілий новий ряд реактивних бібліотек і фреймворків, побудованих на NIO і Netty (великий бібліотеки NIO). Наприклад, Play Framework є повністю реактивним веб-фреймворком, який багато людей використовують з реактивними бібліотеками баз даних, таких як Reactive Mongo .

Бути Реактивним означає, що ви також повинні мати конструкцію для асинхронности. Традиційний спосіб зробити це в Java - з анонімними внутрішніми класами, як:

  public static F.Promise <Result> index () {

     F.Promise <WS.Response> jw = WS.url ( "http://www.jamesward.com") .get ();

     return jw.map (new F.Function <WS.Response, Result> () {

         public Result apply (WS.Response response) throws Throwable {

             return ok (response.getBody ());

         }

     });

 } 

Java 8 забезпечує набагато більш короткий синтаксис для асинхронних операцій з лямбда. Те ж саме Реактивний обробник вище Java 8 & Лямбда це:

  public static F.Promise <Result> foo () {

     F.Promise <WS.Response> jw = WS.url ( "http://www.jamesward.com") .get ();

     return jw.map (response -> ok (response.getBody ()));

 } 

Якщо ваш додаток робить речі паралельно і / або управляє пуш підключеннями, то ви дійсно повинні бути реактивними. Перевірте мою презентацію Будівництво реактивних додатків , якщо ви хочете зануритися глибше в усі це.

Мова Java типу відстій

У мови Java багато великих аспектів, але через його масивного прийняття і бажання своїх корпоративних користувачів дуже поступової зміни, мова показує свій вік. На щастя, є тонни інших варіантів, які працюють на JVM. Ось короткий список найбільш цікавих варіантів і моїх позитивних і негативних думок за деякими з них:

  • Scala

· Супер

  • Ймовірно, найбільш широко прийнята альтернативна формулювання на JVM
  • Добре працює з Reactive і потребами великих даних
  • Зріла екосистема для бібліотеки, фреймфорков, підтримки і т.д.
  • добре
  • Java сумісність велика, але часто марна, оскільки бібліотеки Java будуються не для реактивних і Scala ідіом
  • Сучасні концепції програмування з дуже потужним і гнучким мовою
  • гнучкість мови призводить до значно різних способів написання Scala, на шкоду універсальної читання
  • Величезне час на навчання через великої кількості функцій
  • погано
  • Groovy

· Супер

  • Велика екосистема бібліотек, фреймворків, підтримки і т.д.
  • Простий мову з декількома дуже корисними функціями
  • добре
  • Взаємодія з Java працює і відчуває себе досить природно
  • погано
  • Я вважаю за краще хороший висновок типу (як Scala) проти Groovy динамічною і додаткової статичної типізації
  • Clojure

· Супер

  • Елегантність Lisp на JVM
  • Зріла екосистема для бібліотеки, фреймфорков, підтримки і т.д.
  • Цільовий JavaScript, здається, хороший, але не основний
  • погано
  • Відсутність деяких конструкцій робить управління великого обсягу коду складним
  • динамічний введення
  • Kotlin

· Супер

  • Взаємодія з Java здається природним
  • Цільовий JavaScript першокласний

· Добре

  • IDE і інструменти збірки гідні, але незрілі
  • Сучасні мовні особливості, що не приголомшують
  • погано
  • Невизначеність, де він буде протягом 5 років - чи досягне він критичної маси?

Починаючи з нового / зеленого проекту, було б легко спробувати нову мову, але більшість підприємств не часто це роблять. Для існуючих проектів деякі структури і інструменти підтримують існуючий змішаний Java з альтернативними мовами для JVM краще, ніж інші. Play Framework / sbt я використовував для цього, але я впевнений, що є й інші, які роблять це також добре. По крайней мере, написання тільки нових тестів в альтернативному мовою JVM може бути чудовим місцем для початку експериментування.

Лямбда Java 8 є хорошим оновленням для Java мови. Лямбда дійсно допомагають знизити шаблонність і добре вписуються в реактивну модель. Але є ще багато інших областей, де мова відстає. З того моменту, як я спробував Scala, я не можу жити без кількох речей, які до сих пір відсутні в Java: Тип Висновку, зіставлення зразків, Case класи, строкова інтерполяція, і незмінність. Також дуже приємно мати Option, і паралельні конструкції запечені в основнову і екосистеми бібліотеки.

Перевірка в реальних умовах

Якщо ви працюєте в типовому підприємстві то, можливо, вам пощастило, і ви вже робите більшість з описаного. Шокуюче, як це може здатися декому з нас, це дійсно рідкість. Більшість з вас, ймовірно, читаєте це і вам сумно, тому що переміщення підприємства до багато чого з цього матеріалу дійсно важко. Як фізика говорить нам, що набагато важче переміщати великі речі, ніж маленькі. Але не впадайте у відчай! Я бачив ряд великовагових підприємств повільно виповзають з Java відсталих частин. Walmart Canada недавно переїхав на Play Framework !

Моя рекомендація - вибрати одну з цих відсталих речей і поставити мету - виправити її в наступному році. Часто для цього потрібно покупка зі згодою управління, які сприймають покупки жорстко. От моя пропозиція ... Проведіть пару вечорів або вихідні на реалізацію одного з цих пунктів. Потім покажіть своєму менеджеру, що ви зробили в свій вільний час (щоб показати, наскільки ви піклуєтеся), а потім дозволити їм взяти кредит на дивовижний новий предмет, який ви запропонували. Працює кожен раз. І якщо це не проходить, то існує безліч добре оплачуваних стартапів, які вже роблять всі ці речі.

І останнє ... Почитайте Дванадцять чинників додатки -які надихнули мене на цю статтю.