«Сколько зрителей придёт на ваш доклад по Java? Зависит от того, выступает ли в то же время в соседнем зале Венкат».
Это шутка с изрядной долей правды: в Java-мире Венкат Субраманиам — один из самых известных спикеров, действительно способный на конференциях оттянуть зрителей из других залов. Он неустанно перемещается по всей планете и недавно поставил впечатляющий рекорд, к своему 50-летию выступив за один год перед 50 разными Java User Groups.
Каково это, когда твоя Java-карьера — не «сидеть в офисе», а «постоянно перемещаться»? И что Венкат думает об актуальных Java-вопросах? В октябре он доберётся до Петербурга, и в преддверии этого мы (phillennium, olegchir) взяли у него подробное интервью, где начали с «жизни в самолёте» и советов для начинающих спикеров, а затем перешли к технологиям.
Поскольку Венкат отвечает подробно, текст получился длиннющим. При желании можете сразу перейти ко второй части:
- За жизнь
- О технологиях
За жизнь
— Начнём с вашего тура, в ходе которого вы посетили 50 Java user groups, вряд ли кто-либо ранее делал подобное. Какими оказались ваши впечатления?
Поэтому опыт с этими группами был очень полезным для меня. Руководить юзер-группой — это очень сложная… не хочется говорить «работа», поскольку это не работа, но усилий приходится тратить много. Я с огромным уважением отношусь ко всем руководителям, которые вновь и вновь каждый месяц собирают эти мероприятия. У разных групп разная динамика — у одних на встречах присутствует 20 или 30 человек, других — 200 или 300. И тем не менее количество, в сущности, не играет роли, поскольку главное — это страсть разработчиков, приходящих на эти собрания, их интерес к технологиям и их желание учиться. Так что мне очень повезло, что досталась возможность встретиться с этими группами, и я очень благодарен за неё.
— А при упомянутом вами сходстве есть ли у юзер-групп в разных частях света какие-то заметные местные отличия?
— Этих отличий на удивление мало. Я обратил внимание, что в некоторых регионах большее предпочтение отдаётся тяжеловесным фреймворкам, а в других — более лёгковесным решениям. Но, как правило, все эти особенности поверхностны, а глубинные вопросы и проблемы, наоборот, универсальны. Я искренне хотел бы сказать вам, что в некоторой точке на карте люди занимаются совершенно другими вещами, чем мы, и там всё интересно и неожиданно, но я этого сказать не могу.
Мы все стремимся к сложности, она нас затягивает, а когда затянет, мы начинаем с ней бороться. Это общий тренд практически везде. Другая важная проблема, которой не избежал никто — это жёсткие требования бизнеса и недостаток времени для работы над качеством. Я могу рассказывать о некотором примере людям в любой точке Земли, и после моего рассказа меня спросят: «вы случайно не работали в нашей фирме?» Наши проблемы настолько глубинные и универсальные, что, судя по всему, они общие для всего мира. Что невольно заставляет задуматься о нашей общей человеческой сущности, о психологии и философии, которым мы, в конечном итоге, следуем. Сколько бы мы не представляли себя гиками, повёрнутыми на технологии, мы не должны забывать о человеческом аспекте в разработке софта. Судя по всему, он является объединяющей и универсальной силой.
— Хочется поспрашивать о «походном» образе жизни. Когда сидишь в офисе, может быть неочевидно, понравилась ли бы жизнь наподобие вашей. Например, для многих джетлаг — это проблема, и из-за этого постоянные перелёты могут казаться кошмаром. Но, возможно, с практикой к этому приспосабливаешься?
— Чтобы ответить на ваш вопрос, давайте вспомним continuous integration. Если команда выполняет интеграцию раз в месяц, то, предложи вы им выполнять это постоянно, они посчитают вас сумасшедшим. В этом отношения путешествия напоминают непрерывную интеграцию и непрерывную доставку: если заниматься ими достаточно много, ваш подход к ним меняется.
Поймите меня правильно, я не горжусь своим образом жизни, на мой взгляд, так жить не стоит. Я всегда говорю, что в путешествиях мне меньше всего нравятся сами путешествия. Сидение в самолёте утомляет, тело изнашивается, и с возрастом эти проблемы никуда не уходят. Но когда я оказываюсь в точке назначения, когда встречаюсь с другими разработчиками, вижу их страсть к технологии, их воодушевление, получаю возможность разделить эту страсть, научиться чему-то новому и помочь учиться им, все трудности окупаются с лихвой.
Если же говорить именно о смене часовых поясов, то она меня не беспокоит вовсе. Из-за постоянных перелётов у меня в определённом смысле нет постоянного, «домашнего» времени. У меня есть правило: я просыпаюсь всегда в одно и то же местное время, около 3.30 ночи, и тело очень быстро входит в определённый ритм. Ну и, конечно, кофе всегда очень кстати.
— Многие люди хотели бы увидеть мир, но они обычно ездят в туристические поездки, а не в деловые. Удаётся ли вам посмотреть на города, или из-за нехватки времени только на конференц-залы?
— Да, отчасти здесь проблема со временем. Но, помимо этого, из-за постоянных перелётов у меня есть некоторые принципы, которых я придерживаюсь. Если путешествие связано с работой, то ничем, кроме работы, я не занимаюсь. Я стараюсь провести как можно больше времени с разработчиками. Когда у меня есть свободная суббота или воскресенье, например, в Европе, то я обычно трачу её в юзер-группе. Мне доставляет огромное удовольствие общение с разработчиками, поэтому в своих деловых поездках я практически никогда не хожу по достопримечательностям.
Но каждый год четыре-шесть недель летом я путешествую с семьёй, и мы ходим по достопримечательностям. Это наше время совместного отдыха, а в остальные месяцы я сконцентрирован на работе.
Кроме того, мой подход позволяет мне уделять максимальное внимание различным мероприятиям сообщества, что также доставляет мне большое удовольствие. Это поглощает много времени и является своего рода компромиссом, но меня он устраивает. Жизнь иногда слишком напряжённая, и я рад возможности иногда отвлечься и послушать разработчиков, у которых может не быть возможности посетить конференцию или обучающий курс. Кроме того, я считаю, что это в том числе моя профессиональная обязанность, по той причине, что именно эти вещи вдохновляли меня в молодости. Я посещал юзер-группы, слушал выступления и мечтал в своё время также выступать самому. Если мне в свою очередь удастся так же вдохновить хотя бы одного человека, это время будет потраченным не зря.
— Последний вопрос о путешествиях. В фильме «Up in the Air» персонаж Джорджа Клуни, постоянно летающий между городами, знает много приёмов для повышения эффективности путешествий: как стоять в очереди, как упаковывать багаж и так далее. Возможно, у вас тоже есть некоторое неочевидное знание, которым вы хотели бы поделиться?
— Мне стыдно в этом признаться, но я иногда пересылаю одежду между городами по FedEx, потому что у меня попросту нет времени на то, чтобы прилетать домой и брать одежду на следующую неделю. Часто, когда я прибываю в отель, моя одежда уже лежит там, а когда я уезжаю, я отправляю её домой. К счастью, это происходит не слишком часто, возможно, три или четыре раза в год, когда я нахожусь в пути по три недели кряду. Был один неловкий момент, когда моей жене пришлось отправиться в аэропорт, чтобы передать мне сумки, потому что у меня было только полчаса между рейсами. Но со временем действительно учишься делать некоторые вещи более эффективно. Меня иногда удивляет, когда люди говорят «мне нужно собраться», потому что мои вещи всё время собраны.
— Вероятно, из-за вашей известности вам приходит куда больше писем, чем обычным разработчикам. Сколько вам пишут и много ли времени занимает работа с почтой?
— Стоит добавить, что я преподаю в университете и получаю много писем от студентов. Обычно мне приходит 20 или 30 писем в день. Где-то год тому назад я писал в блоге об одном из своих принципов: «ответь сейчас или скажи, когда ответишь».
Я очень ценю своё время, а это значит, что я ценю время других людей. На мой взгляд, уважение к другому человеку заключается не в обращении «sir», а в том, чтобы ценить время друг друга. Поэтому если мне приходит письмо, я всегда отвечаю в течение 24 часов. Но бывают периоды, когда дать полноценный ответ не выходит — например, если организатор конференции просит прислать аннотацию или если коллега по отрасли задаёт вопрос о решении определённой проблемы, просит провести рефакторинг некоторого кода или спрашивает о применении некоторого метода. Иногда ответ может занять десять минут, а иногда два часа, но даже десять минут не всегда можно потратить. Это может прозвучать немного странно, но я всё равно в таких случаях отвечаю в течение 24 часов и пишу: я получил ваше письмо, я поработаю над этой проблемой, скажем, 2 сентября и напишу вам 3-го. Одновременно с этим мой календарь пополняется соответствующей записью в день, когда у меня есть время в полёте или после обеда.
Благодаря такому подходу мой ящик входящих сообщений всегда пуст, я чищу его каждый вечер перед сном. Так что я крайне дисциплинированно отвечаю на письма. Люди часто удивляются, что я так быстро отвечаю на их письма, а я, наоборот, не понимаю, как можно иначе. Я не хочу стоять на пути у людей, мешать им развиваться. Кроме того, я считаю важным способность сказать «нет». Я люблю повторять, что чем чаще вы говорите «да», тем хуже у вас будет получаться то, что вы делаете. В определённый момент нужно осознать, что мы не можем достичь всего на свете. Поэтому иногда я отвечаю, что, к сожалению, не могу ничем помочь. В свою очередь, я предпочитаю, чтобы мне говорили «нет» сразу, а не тянули резину и говорили «нет» потом. На мой взгляд, это тоже говорит об уважении к человеку и нежелании тратить его время впустую. Вы не обязаны помочь, но, по меньшей мере, не мешайте. Поэтому важно говорить «нет». Так устроена жизнь, не стоит пытаться сделать вид, что вы можете успеть всё на свете. Для меня умение быстро и честно отвечать является знаком профессионализма.
— Вы очень опытный докладчик. Как организаторы конференций, мы встречаем людей, которые не имеют опыта публичных выступлений или имеют совсем немного. Возможно, у вас есть рекомендации для них? У вас в твиттере был интересный совет «заранее посетить зал, в котором будет проходить доклад» — есть ещё подобные?
— Мои первые доклады были в юзер-группах, именно поэтому я продолжаю делать в них по 15 докладов каждый год. И я рекомендую другим начинать с этого же: с юзер-группы в вашем регионе, потом в соседнем и так далее.
На этих докладах по многим причинам меньше рисков, чем на большой конференции: там дружественная обстановка, люди приходят туда, чтобы делиться знанием, после ваших докладов вам легко будет получить отклик. Вы вполне можете начать выступление, сказав, что у вас в этом деле мало опыта и вы хотели бы узнать мнение слушателей. В этом году у меня был новый доклад, при подготовке которого я достаточно много переживал. Я писал об этом в твиттере: кажется, что всё можно сказать за две минуты, а в реальности материал не удаётся уложить в полтора часа. И я очень рад, что первый раз с этим докладом я выступил в юзер-группе, поскольку это дало мне возможность лучше подготовить его для конференции.
В юзер-группах или в компании, где вы работаете, у вас есть замечательная возможность попрактиковаться с выступлениями. Во-первых, вы получите критику от коллег, что позволит вам улучшить доклад. Во-вторых, даже если прямо вам ничего не скажут, вы всё равно многое поймёте сами, когда начнёте говорить. Я считаю, что по-настоящему улучшить доклад удаётся с третьего раза. В первый раз вы только пытаетесь свести все мысли вместе. И вот что интересно: практиковаться в одиночку здесь не поможет, осознание проблем приходит только во время выступления перед другими людьми. К третьему разу логическая цепочка вашего повествования становится более ясной для вас, оказывается завершённой. Это не всегда заметно, но я иногда приостанавливаюсь во время выступления на третий раз — в этот момент я осознаю, что именно я пытался сказать в докладе, наступает своего рода момент истины. Итак, очень важна практика, но не наедине с собой, а с людьми. Молодому разработчику это может придать необходимую уверенность.
Правда, некоторые делают свои первые доклады на конференциях. Иногда для человека проще умереть, чем выступить на публике, и их легко понять — это требует очень много нервов. Два или три года назад я выступал на одной конференции. Ко мне подошёл очень заинтересованный человек и сказал, что я, по-видимому, сильно переживаю, на что я ответил, что это действительно так. Он спросил «Это ваш первый доклад?», а я ответил: «Нет, скорее десятитысячный, потому и переживаю». Каждое выступление перед публикой требует большого эмоционального напряжения, даже если у вас есть большой опыт, просто потому, что вам небезразлично, как пройдёт доклад. Вы сослужите себе большую службу, если облегчите это напряжение несколькими пробными докладами в группах пользователей или в вашей компании. Это касается всех докладчиков, в том числе опытных.
— А есть в публичных выступлениях что-то, чего, наоборот, следует избегать?
— Я совершил много ошибок в моей жизни, которые научили меня, что лучше всего люди учатся на опыте. Когда вы выступаете перед аудиторией, нужно помнить о нескольких вещах. Во-первых, нужно сохранять уверенность в себе: вы много работали над темой, и много о ней знаете. Во-вторых, помните: знать всё невозможно, и незнание чего-либо не является вашим недостатком. Это просто значит, что у вас не было возможности уделить этому внимание, и ничего зазорного в этом нет. Крайне важно честно себе в этом признаться. Вы вполне можете ответить на вопрос на конференции так: извините, я не могу вам ничего сказать, у меня не было возможности изучить эту проблему.
Другой важный момент заключается в том, что слушателей можно разделить на три типа. Есть люди, которые хотят научиться у вас чему-то новому. Другие держат себя несколько более осторожно, они будут вас слушать, но не готовы будут воспринять всё, что вы говорите. Наконец, есть и третья группа людей, к счастью, довольно малочисленная: те, кто настроены враждебно, и всё время пытаются вас подловить. Рано или поздно на вашем докладе обязательно будет один разработчик, который всё время будет вас прерывать и нарушать ход доклада. В таких случаях очень важно сохранять спокойствие, позволить ему выговориться и вернуть дискуссию в необходимое вам русло — но, нужно признаться, я тоже человек, и у меня далеко не всегда получается это сделать. Можно, например, сказать: я понимаю, что для вас это важно, давайте обсудим это после доклада, эта тема для многих здесь важна. Правда, очень часто у вас находятся союзники в аудитории, и, когда человек действительно нарушает ход выступления, его просят успокоиться. Всё это я говорю к тому, что важно не быть слишком конфликтным в таких ситуациях, хоть наша природа может этому и противиться. Будучи ещё молодым докладчиком, я довольно часто вступал в такого рода конфронтации на полную силу, и это никогда никому не приносило ничего хорошего. Необходимо проявлять эмоциональную зрелость и не пытаться никому ничего о себе доказывать, вступая в такого рода перепалки. Вместо этого в таких случаях следует уводить тему назад к тому, что интересно аудитории.
Хотел бы также рассказать о некоторых отрицательных привычках во время выступлений, которые, на мой взгляд, есть у разработчиков. Для начала, людям следует смотреть в глаза. Я понимаю, что это очень тяжело и требует большого эмоционального усилия, но в этом нужно практиковаться. Докладчики часто смотрят на свой монитор или, ещё хуже, на экран, встав спиной к аудитории. Всегда нужно быть обращённым лицом к слушателям и всегда следует смотреть на них. Кроме того, необходимо сохранять уверенность в себе. Вы выступаете перед аудиторией программистов, и можно побиться об заклад, что ни у одного из них код не работает с первого раза. Если ваша демонстрация во время доклада не сработала — в этом нет ничего зазорного. Все присутствующие скорее всего подумают: «Чёрт, у меня всё точно так же». С годами я научился в таких ситуациях обращаться к аудитории за помощью с отладкой. Обычно докладчики в такой ситуации начинают бормотать себе что-то под нос и пытаются решить все сложности самостоятельно. Вместо этого следует спросить аудиторию — друзья, не подскажете, где я туплю? Вам тут же поступит множество предложений, и очень часто они помогут вам найти ошибку. Говорить и писать код одновременно одному человеку сложно, не бойтесь попросить о помощи. Для слушателей этот опыт также ценен. Это одна из причин, по которой я посещаю доклады других людей: посмотреть, что они делают, и понять, чего именно делать не следует. На мой взгляд, эти привычки помогут вам провести рефакторинг ваших навыков докладчика.
О технологиях
— Автор известных Java-книг Кай Хорстманн рассказывал нам, что предлагал упростить в Java создание «Hello world». Потому что новички при виде «public static void main» сталкиваются со множеством новых понятий одновременно, и это отпугивает, разумнее более постепенный вход.
Интересно вот что: Java-разработчики редко задумываются о пользе подобного, потому что им эти вещи уже кажутся само собой разумеющимися, а Хорстманн это понимает, потому что преподаёт в университете и лично видит испуг на лицах студентов. Вы как преподаватель, автор книг и докладчик тоже учите людей. Вам из-за этого тоже хочется что-то изменить в Java?
— Да, определённо. Больше того, это одна из тех вещей, которые меня привлекают в Java — это уже совсем не тот язык, каким он был в 2000-м. За последние несколько лет создатели языка стали осознавать, что когда язык становится многословным и напыщенным, это существенно затрудняет работу программистов, причём не только начинающих.
Предположим, вы общаетесь с вашим коллегой, вас посещает некоторая новая мысль, но она не сразу очевидна вашему собеседнику, и он просит вас продемонстрировать, что именно вы имеете в виду. Вы открываете редактор, и в первые же секунды осознаёте, что для реализации этой идеи вам нужно написать 70 try-catch блоков. И, хоть идея и хороша, вы решаете оставить её на потом, потому что прямо сейчас может не быть времени.
Именно поэтому Java 12, 13 и 14 эволюционируют в эту сторону: разработчики осознают, что, хоть Java и крайне мощный язык, с ним не очень просто экспериментировать, и ему сложно учиться. Когда вы точно знаете, что именно хотите написать, Java работает идеально, но обычно программирование выглядит иначе. Вы всегда учитесь и экспериментируете, у вас всё время рождаются идеи, которые ранее казались бы невозможными. Если я работаю в компании с наработанной базой кода и определённой структурой кода и если я добавляю приложению новые возможности на основе уже существующих шаблонов, эти изменения меня существенно не затронут, здесь Java прекрасно работает в уже существующей форме. Но если вы архитектор, тимлид или просто программист, который пишет код новаторски и экспериментирует, то Java в сегодняшнем виде будет во многом вас ограничивать. Поэтому, на мой взгляд, важно, чтобы языки эволюционировали в сторону меньшей напыщенности, и я большой сторонник того направления, в котором Java сейчас изменяется.
Минутка рекламы. В октябре Венкат откроет нашу петербургскую конференцию Joker выступлением «Don't walk away from complexity, run». И, поскольку каждый докладчик Joker после выступления отправляется в дискуссионную зону, там будет возможность лично обсудить с ним и тему выступления, и другие вопросы.
— В контексте «менее напыщенная Java» невозможно не спросить вас о Kotlin, который часто так и называют.
Меня в программирование привели наука и математика, но 30 лет спустя остаюсь я программистом благодаря тому, что это искусство. Наша область сочетает науку и искусство, от этого никуда не деться. Умением просто заставить систему работать дело не ограничивается, здесь можно провести аналогию с написанием стихов: попросите двух человек написать о любви, и каждый напишет по-своему. Код для любого задания можно написать множеством различных способов. Именно это меня привлекает в языках наподобие Kotlin и многих других: возможность выражать некоторые из этих идей, придавать коду гибкость и лёгкость. Вы можете значительно меньше думать о синтаксисе языка и больше — о той мысли, которую хотите передать.
— Для вас имеет большое значение качество кода. Оно вроде как для всех важно, и вроде как все хотят писать лучше, но при этом известно, что у значительной части существующего кода есть проблемы. Поэтому такой вопрос: чтобы за ваш код вас потом не ненавидели коллеги, нужна просто самодисциплина, можете дать какие-то конкретные рекомендации?
— Я убеждён, что единственный способ написать читаемый код — это прочитать его. Когда мне говорят, что код читаемый, я спрашиваю — кто его читал? Если его прочитал сам автор непосредственно после написания, это не считается. Поэтому я убеждённый сторонник код-ревью. Хочу пояснить: я против того, чтобы приводить команду в комнату с большим экраном, показывать на нём код и критиковать его. Это неизбежно приводит к обидам, такое публичное охаивание никому на пользу не идёт.
Ещё один важный момент: не надо говорить человеку, что он сделал ошибку, надо сказать, что именно можно улучшить. Не говорите: «Боже, какое жуткое название переменной», лучше так: «Ты, наверное, хотел сказать, что эта переменная показывает частоту распределения — наверное, её следует назвать соответствующим образом». Это поможет вам лучше передать ваши намерения. Это также касается редактуры книг: говорите не только о том, что нужно улучшить, но и о том, что было сделано хорошо. Мы это часто забываем. Когда я редактирую чужой код и вижу место, которое качественно выполнено, я пишу в комментарии, что мне оно очень нравится, что нам нужно чаще так делать, и объясняю, почему именно. Это создаёт конструктивную обратную связь, даёт разработчику понять, что вы не настроены к нему враждебно, и в конечном итоге улучшает качество кода вашей команды.
— Вы писали, что пользоваться инструментом, который вгоняет вас в тоску — это как застрять в токсичных отношениях: в такой ситуации нужно просто уходить, и как можно скорее. Это звучит замечательно, но зачастую у инструмента нет особой альтернативы, и что делать тогда?
Когда же выбора нет, вместо того, чтобы жаловаться, следует обозначить болевые точки: что именно делает этот инструмент неудобным для вас. А дальше можно поступать разными способами. Можно связаться с разработчиками и сказать — спасибо за ваш труд, нам кажется, что ваш инструмент мог бы быть значительно лучше, если бы вы обратили внимание на такой-то и такой-то аспект. Либо можно провести хакатон — собраться на выходных вместе с несколькими разработчиками, организовать юзер-группу, сказать им, что вы проводите по девять часов в день с этим инструментом, что он ужасен, и попросить попробовать добавить к нему некоторые возможности.
Быть может, вы не сможете решить все проблемы в одиночку, но по крайней мере вы сможете собрать других людей и вместе с ними решить эту задачу, в особенности если их интересы схожи с вашими. Наконец, если ваш инструмент действительно доставляет вам столько проблем, можно попробовать написать новый самостоятельно — в том случае, если у вас есть трое или четверо знакомых в сообществе с таким же настроем, что и у вас.
Так что, на мой взгляд, альтернативы всё-таки есть. Вам не обязательно мириться с токсичными отношениями. Всегда нужно уметь найти выход — либо договориться с партнёром и добиться взаимопонимания, либо уйти.
— Вы написали книгу о лямбдах, и вас знают благодаря этой книге. Я её тоже читал, и считаю, что она прекрасно написана, даёт то, что необходимо разработчику приложений, и не дает ничего лишнего. Как настоящего профессионала я хотел бы вас спросить: что для вас функциональное программирование? Могли бы вы описать это собственными словами? Я задаю этот вопрос потому, что все определяют его немного по-своему, и каждый раз открываются скрытые смыслы, которые отличаются от стандартного определения с Википедии.
— Это замечательный вопрос. Моё понимание этого понятия эволюционировало с годами, и сейчас для меня наиболее главное в функциональном программировании — это удаление посторонней сложности. Речь идёт о том, что в императивном программировании вы не только указываете, что именно нужно сделать, но и детально прописываете, как это нужно сделать. Для меня функциональное программирование является надстройкой над декларативным стилем программирования, в котором мы указываем, что нужно сделать, но не говорим, как именно.
Приведу примитивную аналогию: мои лучшие друзья обожают машины, а меня машины совершенно не интересуют. Когда мы собираемся вместе, мы договариваемся не обсуждать машины, потому что хотим остаться друзьями. Я никогда не буду водить машину с ручной коробкой передач — необходимость постоянно переключать передачи портит мне всю езду, и то же самое относится к императивному стилю программирования. Автоматическая коробка передач немного упрощает езду, но по мне лучший вариант — чтобы меня вёз водитель. В этом случае я только говорю, куда мне нужно попасть, и по пути пишу код на своём ноутбуке на заднем сидении. Для меня в этом отличие между императивным и функциональным программированием. При императивном программировании вы сами за рулём, вам нужно знать, куда ехать, как ехать, где поворачивать, где можно срезать. При функциональном программировании вы сидите на заднем сидении, говорите водителю, куда вас отвезти, и ваше внимание целиком сконцентрировано на вашей работе.
Каким же образом происходит удаление этой посторонней сложности? Через композицию функций. При композиции функций ваш код проходит ряд преобразований, в ходе которых данные переходят из одной формы в другую. Причём для нас важно не то, как каждый из этих шагов выполняется, а чего именно он достигает. Для меня первый аспект функционального программирования — функциональная композиция. Проблема в том, что многие языки, в которых реализована функциональная композиция — Ruby, Python, JavaScript, Groovy и так далее — обеспечивают благодаря этому элегантность и выразительность, но обладают весьма низкой производительностью. Функциональная композиция в них реализована неэффективно. Я же считаю, что элегантность без эффективности нежизнеспособна. Мало того, чтобы код был красивым, он также должен быстро работать. И здесь мы подходим ко второму, жизненно важному аспекту функционального программирования — речь идёт о ленивых вычислениях. Результат определённой функции рассчитывается только в тот момент, когда он оказывается необходим. Благодаря этому в функциональном программировании достигается сочетание элегантности и эффективности. Итак, для меня функциональное программирование — это акцент на том, что делать, а не как делать; использование функциональной композиции как ряда преобразований данных; и возможность выполнять эти преобразования эффективно благодаря ленивым вычислениям.
Обратите внимание, что я не говорил о иммутабельности и функциях высокого порядка. Дело в том, что они — только ингредиенты для получения описанного мной результата. Мы пользуемся функциональным программированием не для иммутабельности и функций высокого порядка, они только средство для достижения более высокой цели: избавления от посторонней сложности.
— Прекрасное определение. Сегодня существует язык, который является эталоном того, каким должно быть функциональное программирование: Haskell (и, возможно, F#).
— Совершенно верно.
— По крайней мере, многие так считают. Но Java, очевидно, не Haskell, она во многом ограниченна. Имеет ли смысл функциональное программирование как дисциплина в применении к Java? Ведь в нашем языке весьма ограниченный набор средств для такого подхода.
— Для меня скорее важен прагматический аспект, а не стремление к совершенству. Совершенство мне любопытно, но чтобы всё работало, я должен быть прагматиком. Я без ума от Haskell и очень много времени провожу с ним, просто чтобы узнать, как та или иная задача решается в функциональном программировании. Но для моих клиентов я на Haskell не пишу. Здесь можно провести аналогию с «Собором и Базаром». Собор прекрасен, но большую часть времени я провожу на базаре. Вопрос в том, как выжить в этом мире. Когда языки эволюционируют и когда мы пытаемся соединить вместе несколько различных парадигм, нам, как программистам, нужно быть крайне осторожными с их реализацией.
Я не считаю, что в Java функциональное программирование вообще невозможно. В тех ситуациях, когда есть выбор, я остановлюсь на наиболее подходящем мне языке. Но я никогда не скажу клиенту: вам следует использовать этот язык. Чаще всего я спрашиваю, что именно они делают, и пытаюсь найти способ делать то же более оптимальным способом в рамках той среды, которая у них уже существует. Я считаю, что в языках наподобие Java сочетание императивного и функционального программирования вполне возможно и даже рекомендовано, но делать это следует крайне осторожно. Представьте, что у вас есть своего рода круг чистых функций, вокруг которого будет кольцо нечистоты. Всё, что вы хотите сделать изменяемым, должно находиться вне круга. Внутри этого круга вы можете реализовать свою цепь функций, но все изменения должны находится вне него.
Если подумать, то ровно по такой же схеме функционирует Redux. В нём существуют данные и существуют преобразователи reducers. Когда данные отправляются в reducers, вы получаете взамен новую копию, которую сохраняете вместо старой. Но если Elm и Redux функционируют по одной и той же схеме, то такую же схему можно реализовать и в Java. Мы можем создать чистые функции, которые будут брать данные, преобразовывать их и возвращать новую копию. Учась у Redux и Elm, мы можем сделать архитектуру Java более функциональной. Я говорю об этом, потому что Redux компилируется в JavaScript, который однозначно является базаром. JavaScript, я думаю, в наибольшей степени удалён от идеала функциональной чистоты, здесь при каждом шаге вы наступаете в лужу. И тем не менее Redux даёт вам функциональную чистоту в этом крайне нечистом мире. На меня этот подход сильно повлиял, поскольку он изменил мой взгляд на функциональное программирование и показал, что я могу реализовать эти принципы и в Java.
— Это очень популярный вопрос, но обсуждать его непросто. Мне стыдно сейчас об этом говорить, но я провёл свою юность в отладчике. Причина, по которой я сейчас этого стыжусь, заключается в следующем: утром, приходя на работу, я находил курсор на той же позиции, на которой оставил предыдущим вечером, потому что был настолько уставшим, что не мог продолжать отладку. С годами я освоил разработку через тестирование, и сейчас я это делаю весьма дисциплинированно. Приведу пример. В приложении, которое мы сейчас разрабатываем вместе с клиентом, у нас, вероятно, миллионы лямбд. Это проект про Big Data. Мы запускаем параллельный код, который постоянно выстреливает кучей лямбд. Как вы понимаете, система не всегда работает ожидаемым образом. И всё же, когда это случается, мы обычно узнаём об этом потому, что не срабатывает юнит-тест. Тогда мой клиент ставит точку останова в тесте, где произошла ошибка, и отлаживает этот тест. Благодаря этому мы отлаживаем не огромные массивы кода, а отдельные модули.
Другими словами, зачастую невозможность отладить код является следствием не качеств определённой технологии, а недостаточной модульности кода. Чем больше модульности, тем более контролируемым становится код. Это верно как по отношению к параллельным вычислениям и лямбдам, так и по отношению к асинхронности. Если у нас несколько тредов и нам трудно их отлаживать, это вполне ожидаемо, поскольку многопоточность по своей природе недетерминированна. В сущности, вы открываете клетки в зоопарке, а затем пытаетесь понять, куда вам убегать. Ваша задача заключается в том, чтобы укротить этот зоопарк, обрести над ним контроль, а для этого необходимо сделать код модульным. То же самое касается лямбд. Когда меня спрашивают, как я отлаживаю лямбды, я отвечаю: никак. Вам не нужна лямбда, состоящая из 30 строк кода. Вам необходима отдельная функция, для которой у вас будет юнит-тест, которую вы отладите и которую затем вызовете как ссылку на метод через лямбду.
Асинхронность прекрасна, и вот почему. Вы делаете вызов, и указываете, что именно выполнять, когда этот вызов будет завершён. Но этот следующий этап вовсе не обязательно должен быть вызван изнутри асинхронного вызова. Следующий метод можно вызвать отдельно для отладки и тестирования. А сам асинхронный метод не обязательно выполнять, вместо него у вас может быть заглушка, которая просто проверяет, осуществлён ли вызов или нет. Повторюсь: невозможность отладить код чаще всего не является следствием свойств определённой технологии, а указывает на недостаточную модульность кода. И чем дальше я работаю со многими технологиями одновременно, тем больше я в этом убеждаюсь и тем больше нахожу способов активной отладки, которые позволяют при этом не потерять рассудок.
Возвращаясь к другому вашему вопросу — событийно-ориентированные системы (event-driven systems), на мой взгляд, являются будущим программирования. И они хорошо сочетаются с асинхронностью, а также с микро-сервисами. Многие из этих технологий, приложений, API и библиотек существуют уже значительное количество лет, но сейчас вокруг них поднялся настоящий бум. Благодаря их взаимодействию меняется наше представление о том, как приложения будут разрабатываться в будущем. Если взглянуть назад во времени, то вы увидите, что примерно каждые 5-10 лет меняется наше представление о том, какой должна быть архитектура приложений. От приложений для настольных компьютеров мы перешли к серверным и веб-приложениям, затем к мобильным приложениям, а теперь мы думаем о микросервисах и событийно-ориентированных системах. Я думаю, что сегодня мы находимся в очередной стадии перехода. Когда меня спрашивают, принадлежит ли будущее функциональному программированию, я отвечаю — нет, оно принадлежит реактивному программированию. Потому что для меня реактивное программирование — это функциональное программирование++. Реактивность — это композиция функций и ленивые вычисления в приложении к потоку данных. Так что, на мой взгляд, реактивное программирование не свалилось с неба, а является логическим продолжением функционального. Оно сочетает в себе событийно-ориентированную модель, функциональную композицию, ленивые вычисления, возможность асинхронности. Каждая из этих концепций сама по себе вызывает разве что любопытство, но вместе они приводят к фундаментальным переменам в архитектуре приложений в будущем, поскольку они изменяют инструменты и техники, которые мы применяем.
— Хорошо, то есть эти изменения важны не по отдельности, а вместе.
Вы входите в число Java Champions, ранее были Microsoft MVP, а сейчас пишете на JavaScript, так что хорошо видите три разные экосистемы. Мой вопрос такой: развивается ли экосистема Java в целом или нет и как она выглядит по сравнению с другими мирами? Можем ли мы сравнивать её с .NET, JavaScript или чем-либо другим?
— Многое, к чему Java пока только движется, присутствует в .NET уже какое-то время. С# поначалу был слегка улучшенным вариантом Java, и мы говорили, что C# всё за ней повторяет. Но сегодня ситуация обратная. Лямбды появились в Java на несколько лет позже, чем в С# были добавлены LINQ, которые позволяют писать лямбды, и у которых есть действие и функция (то, что они называют Func). Аналогичным образом асинхронность появилась в C# на несколько лет раньше, чем прозвучало обещание добавить асинхронность в Java. Правда, нужно сказать, что в Java с 2014 года есть CompletableFuture. Но асинхронность появилась в C# задолго до этого.
Похожее можно сказать о Java и JavaScript. Я знаю, что фраза «нам есть чему поучиться у JavaScript» может вызвать испуг, но программисты на JavaScript очень многое повидали и знают, почём фунт лиха. У них есть понятие «callback hell», когда коллбэки плохо сочетаются друг с другом, становится крайне сложно обрабатывать исключения и оказывается очень сложно надстраивать что-либо на функциях обратного вызова, которые должны выполнять асинхронные вызовы. В конечном итоге в мире JavaScript было найдено решение в виде Promises (обещаний), которые являются аналогом CompletableFutures в Java. И всё же нужно признать: красота нашего мира в том, что нет единого правильного метода на все времена. Одно из преимуществ Promises в том, что там возможна композиция функций. Другое преимущество — они могут иметь дело с исключениями и через Promises можно пропускать данные. Однако представьте, что в вашем коде, помимо прочего, есть несколько уровней исключений. Он может стать достаточно сложным, и в определённый момент вы поймёте, что он выглядел бы значительно лучше, если бы был написан в императивном стиле, а не функциональном. Именно поэтому в JavaScript были добавлены async и await. В сущности, они являются императивными оболочками для Promise. Вы можете писать императивный код, и когда в нём делается вызов к функции, этот вызов становится асинхронным, и код под этой функцией выполняется не сразу, а после того, как асинхронная функция уже завершила свою работу. С CompletableFuture это невозможно, но с continuations в Java в будущем это будет возможно. И это именно то, что делают coroutines в Kotlin.
Если мы сравним все эти языки, станет понято, что я полиглот из чисто эгоистических соображений. В определённом смысле программирование на разных языках аналогично путешествию в разные страны. Я обожаю бывать в России, Эстонии, Индии, разных частях США, потому что во время этих поездок я встречаюсь с разными культурами и вижу различные практики, различные способы, которыми люди решают одни и те же проблемы. Поэтому я всегда говорю разработчикам, что одним из важнейших качеств хорошего программиста является понимание того факта, что нет одного единственно правильного способа писать код. Конечно, некоторые способы в некоторых ситуациях обладают преимуществами, другие — недостатками, и нам нужно выбирать то, что лучше подходит. Если сравнить async в C#, async/await и Promises в JavaScript и coroutines в Kotlin, мы увидим, что в одних ситуациях лучше использовать функциональный стиль, в других — императивный, но реализовать асинхронность можно и с тем, и с другим подходом. Мне это кажется крайне любопытным. Java в области этих нововведений отстаёт от других языков. Но я считаю, что Java меняется не только потому, что эти изменения уже произошли в других языках, но и потому, что меняется среда, в которых мы создаем эти приложения. Язык должен эволюционировать, чтобы обеспечить возможность создавать современные приложения. Я думаю, что язык, который перестаёт удовлетворять требованиям бизнеса, становится устаревшим и выходит из употребления. Java должна эволюционировать, чтобы выжить. И я не слишком обеспокоен тем, что Java отстаёт от некоторых других языков — у неё ещё есть время.
Я очень ценю ещё один аспект Java. Давайте взглянем на лямбды. Я обычно говорю, что Java опоздала на праздник, но принесла отличный десерт. Лямбды в Java появились очень поздно, но их реализация при помощи invokedynamic, на мой взгляд, потрясающая. Она улучшает использование лямбд на всех языках, работающих на JVM. Java не является новатором в области языков, но она — новатор в поиске более совершенных способов реализации. И, на мой взгляд, это весьма существенное преимущество. Я думаю, в будущем другие языки будут продолжать опережать Java с точки зрения доступности новых возможностей, но Java будет отыскивать лучшие, более практичные и высокопроизводительные способы реализации этих технологий на JVM. А нам ведь это и нужно. Нам не нужны новые возможности просто для красоты, нам необходим код, который отвечает предъявляемым нам требованиям. С этой точки зрения тот факт, что Java развивается не слишком быстро, является преимуществом.
— Хорошо. Теперь, наверное, последний вопрос от меня, и он будет касаться темы многоязычности. Мы живем в очень сложном мире, больше нельзя записать все что угодно за 5 строчек ассемблера. Несколько строчек ассемблера — это недостижимый идеал. Испокон веков существали языки с гибким синтаксисом — скажем, Common Lisp, в котором можно создать свой собственный JavaScript при помощи Meta Object Protocol, а сегодня существуют крутые способы писать DSL типа Kotlin или JetBrains MPS, при помощи GraalVM скоро можно будет написать компилятор Java на Java и так далее. При желании можно написать проект на двадцати языках программирования сразу. Каким образом возможен контроль над сложностью в многоязычном мире с динамическими и меняющимися каждый день правилами?
— Это крайне важный вопрос. Я всегда говорю, что надо стараться избегать увлечения технологией. Под увлечением я имею в виду ощущение, когда вы видите нечто новое и вам кажется, что это непременно нужно использовать в вашем приложении прямо сейчас. Тут нам как разработчикам необходимо над собой работать. Во-первых, нам не следует учиться новой технологии только потому, что она нужна на текущем проекте. Во-вторых, нам не следует применять всё, чему мы научились. Я говорю это потому, что многие из вещей, которым я научился, я не применяю по шесть или по семь лет. Я изучал эти технологии не для непосредственного применения, а чтобы иметь представление об их существовании. Нужна определённая мудрость, чтобы решить, что в данном проекте эта технология пока что не нужна. Сложность возникает тогда, когда мы сваливаем в кучу разные компоненты, не до конца поняв их достоинства. Например, когда я прихожу на сайт клиента, я всегда спрашиваю: зачем вы используете это? Больше того — зачем вы пытаетесь решить эту проблему? Почему она настолько же важна, как и то множество других проблем, которые вы решаете? Поэтому я рекомендую разработчикам не торопиться и разобраться, зачем была создана интересующая их технология. Я часто спрашиваю их: можете ли вы сказать, когда и в каких условиях вы стали бы использовать Angular, а когда — React? Иногда люди не могут ответить, но при этом в своём проекте они используют React. Мой вопрос в таком случае — а действительно ли вам он здесь нужен? Я не говорю, что он не нужен, но мы зачастую не знаем, зачем мы его используем и просто делаем так, потому что кто-то сказал, что так надо. Сложность возникает тогда, когда мы используем технологии, не до конца понимая их предназначение. Бороться с ней можно, изучая эти технологии и сравнивая их друг с другом, оценивая преимущества и недостатки. Если разработчик не может назвать мне пять аспектов, которые его привлекают в некотором инструменте, и пять — которые отталкивают, это значит, что он недостаточно изучил этот инструмент. Когда мы увидим каждый инструмент с разных сторон и получим непредвзятое представление о нём, мы сможем его успешно использовать.
Последнее, что я хотел бы сказать о сложности. Когда вы оцениваете технологию, избавляйтесь от ваших эмоций и желаний. В наших обсуждениях обычно кто-то говорит: мне нравится та или иная технология, я хочу её использовать. Я рекомендую командам начертить таблицу и перечислить в ней возможности, которые необходимы вашему приложению: тестируемость, масштабируемость, асинхронность, безопасность и так далее, в зависимости от приложения. Затем напротив каждой напишите цифру от 1 до 10, где 10 значит «крайне важно», а 1 значит «безразлично». После этого для каждой возможности напишите список существующих технологий и для каждой проставьте цифру от 1 до 10, где 1 значит «не поддерживает», а 10 — «осуществляет превосходно». Наконец, подсчитайте очки и посмотрите, какие из существующих технологий заработают больше всего баллов. Теперь ваши эмоции никак не участвуют в оценке, и это позволяет более осмысленно выбрать необходимую технологию. Вы делаете эту оценку не в глобальном масштабе и даже не в масштабе фирмы, вы её делаете исходя из потребностей текущего проекта. Поэтому мне не нравятся заявления некоторых компаний о том, что у них Angular, React или Java является общим стандартом. Я всегда спрашиваю в таких случаях: для чего именно? Мы даже ещё не знаем, что именно будем делать. Это всё равно, что сказать: вся наша компания будет передвигаться исключительно на велосипедах. Это ведь бессмысленно. Всё зависит от того, чем именно мы занимаемся, и это тот вопрос, который на который нужно ответить в первую очередь. В общем, я считаю, что сложность можно существенно сократить, если правильно понять, что именно мы делаем и зачем мы применяем ту или иную технологию; если избавиться от эмоций и желаний и подвести счёт ресурсам и потребностям; если правильно оценить сопоставимость имеющихся у нас решений.
Наконец, последнее, что я хотел бы упомянуть — это минимализм. Я всегда говорю командам — добавлять вещи в проект легко, удалять их из проекта крайне сложно. Издержки по удалению в десять раз превышают издержки по добавлению. Поэтому при добавлении чего-либо нужно быть уверенным, что вы действительно сокращаете издержки не только прямо сейчас, но и в долгосрочной перспективе. И нужно, помимо прочего, думать об обратимости. Речь идёт о возможности откатить решения, принятые об архитектуре приложения. Если решение является обратимым, то завтра вы можете от него отказаться, и в этом случае слишком долго раздумывать о нём не следует. Если же решение плохо обратимо, то на него нужно потратить больше времени, собрать больше данных. Если мы учитываем степень обратимости наших решений, то мы тем самым существенно способствуем снижению сложности приложений. В целом, я считаю, что мы должны во многих аспектах преодолеть наше увлечение технологиями, чтобы сократить степень сложности.
— Спасибо, это прекрасный ответ. На нашей конференции Joker вы как раз тоже будете говорить о сложности, так что можно будет продолжить обсуждение там.
— Да, я с воодушевлением буду этого ждать.
Источник: https://habr.com/company/jugru/blog/423271/?utm_source=habrahabr&utm_medium=rss&utm_campaign=423271
Смотри также:
Зачем нужна Java. http://fetisovvs.blogspot.com/2014/07/java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html
Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html
JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
Руководство по Java 9 для тех, кому приходится работать с legacy-кодом. http://fetisovvs.blogspot.com/2018/08/java-9-legacy-java.html
Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html
Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html
Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
Раздача халявы: нетормозящие треды в Java. Project Loom. http://fetisovvs.blogspot.com/2018/09/java-project-loom-java.html
Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html
Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html
Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson,
LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html
Java EE Concurency API. http://fetisovvs.blogspot.com/2018/08/java-ee-concurency-api-java.html
Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
Максимально простой в поддержке способ интеграции java-клиента с java-сервером. http://fetisovvs.blogspot.com/2018/09/java-java-java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html
Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html
JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
Руководство по Java 9 для тех, кому приходится работать с legacy-кодом. http://fetisovvs.blogspot.com/2018/08/java-9-legacy-java.html
Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html
Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html
Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
Раздача халявы: нетормозящие треды в Java. Project Loom. http://fetisovvs.blogspot.com/2018/09/java-project-loom-java.html
Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html
Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html
Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson,
LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html
Java EE Concurency API. http://fetisovvs.blogspot.com/2018/08/java-ee-concurency-api-java.html
Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
Максимально простой в поддержке способ интеграции java-клиента с java-сервером. http://fetisovvs.blogspot.com/2018/09/java-java-java.html
Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html
Проекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html
Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html
Блеск и нищета Java для настольных систем. http://fetisovvs.blogspot.com/2018/04/java-haulmont-java.html
Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html
Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html
Открытый урок Java Enterprise «CDI in action». http://fetisovvs.blogspot.com/2018/09/java-enterprise-cdi-in-action-java.htmlПроекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html
Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html
Блеск и нищета Java для настольных систем. http://fetisovvs.blogspot.com/2018/04/java-haulmont-java.html
Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html
Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html
Комментариев нет:
Отправить комментарий