Developer's mind
563 subscribers
16 photos
18 links
Программирую, обучаю, делюсь опытом
java/kotlin, spring boot, clean code, databases
обратная связь:
@Hcd5opza9bdcjid26fg
https://t.me/developers_mind
Download Telegram
еще из последней недели
"задача выложить наш апи в паблик т.к. новый продукт запускаем"
"ало, давайте закроем все внутренние сервисы за одним общим апи-сервисом, это позволит нам гибче распоряжаться внешним видом апи и уменьшит связность своих сервисов и внешнего апи"
"нет времени на ерунду, давай делать в рамках текущих сервисов"

...

"слушай тут такое дело, у команды php вот такое апи, поэтому надо переделать примерно всё, что бы похоже сделать пути и параметры, а то ведь в паблик выкладываем..." 😂
Сижу я читаю твиттер в последнее время и наткнулся на всякие интересные программистские активности типа #100daysofcoding. Спасибо коронавирусу, видимо. А они делают какие-то проекты и отчитываются между собой в онлайне и все так весело и задорно :) Ну и я решил тоже что мне пора обновить портфолио пет-проектов, изучить что-то новое и попробовать себя в смм и ведении каких-то площадок более плотно.
Поэтому решил замутить такое: https://github.com/asundukov/testfor.us
Что это будет? визард для создания онлайн-тестов и опросов. Довольно интересная структура получается из-за наличия 2-3 видов пользователей, можно что-то нового выдумать или попробовать новые подходы. Бекенд - kotlin и Spring Boot. По фронтенду еще не решил.

На будущее есть еще пару задумок чем заниматься в свободное от работы время.
Вот такую штуку от нечего делать я написал за последние пару недель. Это всё выродилось в довольно большую историю и у меня даже получился kotlin-framework для создания stateless-ботов, что я даже оформил это на гитхабе (закос под профи, хаха) - https://github.com/asundukov/kotlin-telegram-framework

А так теперь "мемогенерящего" бота может себе запилить любой скачав исходники с моих репозиториев и запустив это у себя на сервере.

Шучу, конечно я уже это запустил - @MemeBuilderBot
На днях собеседовался в одну компанию в Польшу. В целом меня оценили очень хорошо, но один коммент меня удивил:
Andrei has in general quite long experience in IT but still, he doesn't know some term, names popular in IT words (TDD, SOLID, YAGNI ... )

Что ж! С них и начнем!
DRY

DRY или Don't Repeat Yourself (не повторяй себя), - наверное, один из самых несложных принципов программирования. Он сводится к тому, чтоб каждый кусочек информации в IT системе был представлен в единственном варианте во избежание дублированного представления. Если мы говорим непосредственно про код, то придерживаясь этого принципа во время разработки позволяет вам:
👍🏻 поддерживать минимальное количество кода при той же функциональности
👍🏻 избежать наличия тех багов, от которых вы уже избавились - отсутствие дублирующихся частей кода позволяет избежать необходимости копипаста исправлений при любом исправлении
👍🏻 уменьшить связность кода за счет того, что внешние зависимости используются в каждой части только в единственном экземпляре

Не стоит так же забывать о том что DRY вполне себе тесно связан с качеством кода, в частности с принципом Single Responsibility. В случае SRP это происходит, потому что вам приходится выносить общие кусочки кода в отдельные общие методы, что уменьшает зону ответственности каждого метода.

"Сухого" вам кода ;)

#DRY #SRP
Проектная терминология

Вы когда-нибудь сталкивались с проблемой когда у вас в системе есть 2-3 или больше ролей, часть из которых для других являются "пользователями". В итоге получается такая ситуация когда термином "пользователь" в вашей системе обознаются несколько совершенно не связанных бизнес-сущностей, а помимо этого и сами пользователи называются пользователями. В итоге на некоторых совещаниях можно услышать "Пользователь-админ создает пользователя-модератора, у которого есть право модерировать сообщения пользователей в чате, чтоб пользователи не испытывали проблем с другими пользователями. Но что мы будем делать с VIP-пользователями пользователей-рекламодателей?". Все это приправляется тем что под словом пользователь каждый участник встречи понимает примерно разное - для кого-то сущность в системе с id, user и email, для кого-то - человек сидящий с лэптопом дома. В итоге на каждом совещании мне приходилось держать в голове примерное понимание значения терминов для каждого участника митинга, а потом еще и разруливать споры, возникающие на основе этого смещения смысла.

Примерно с тех пор на каждый командный проект, в котором мне приходилось участвовать с самого начала, я создаю документ (или часть тз) с названием "Терминология". Основной смысл - договориться со всеми участниками проекта о том, что конкретно мы называем и какими терминами. Это позволяет избежать ситуаций, когда один термин начинают обозначать 2-3 сущности, тогда как другая сущность выражается сразу терминами "мерчант", "продавец", "торговец", "магазин" и т.д.

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

☝️ Не забывайте мэтчить термины перед обсуждением, спором или стартом проекта ;)
Чему учить джунов

Немного с болью наблюдаю как на некоторых проектах джунов кидают в легаси со словами "ГОД ЗА ДВА".

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

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

Что в итоге? Никакого clean code, сплошные if'ы, тестов нет. Растет новый "сениор".

#cleancode #juniors
#риторическийвопрос

Полет на марс

🌌 Не так давно смотрел ролик про марсоходы, в частности посадка Curiosity на марс, представляете насколько волнительно наблюдать инженерам за работой своего детища в плохо изученном окружении (environment) в самый сложный момент и опасный момент - выбор точки посадки, нагрузка при торможении, довольно сложная последовательность предпосадочных операций, реактивное торможение, "небесный кран". И все это - без возможности управления и с пингом в 10-20 минут?

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

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

🧠 В общем - в моей голове этот вопрос уже долгое время остается нерешенным и становится риторическим.

#security #management
SOLID

👆 SOLID - одни из самых известных принципов для написания качественного ООП кода. Насколько бы простыми и интуитивно понятными они не казались - в своем конечном варианте они были сформулированы только в 2000м году Робертом Мартином.

👉 Я тоже считаю считаю их очень важными для написания качественного читаемого кода. Читаемость (или читабельность) - это вообще один из самых важных факторов вашего кода - ведь будь то большой проект или маленький пет-проект - вам приходится именно читать код в разы больше, чем его писать. Любой баг, любая фича, любой вопрос - это повод к тому, чтобы сесть и прочитать кусок кода.

👇 В первый раз когда я про это прочитал и осознал - у меня буквально перевернулся взгляд на то, как писать код, почему его надо писать по-другому. Итак:

🪑 SRP (Single Responsibility Principle) - Принцип единственной ответственности. О том, что каждый класс должен отвечать за одну и только одну функциональность.
🚪 OCP (Open-Closed Principle) - Принцип открытости закрытости. О том, что классы должны быть открыты для расширения, но закрыты для изменения.
👨‍👩‍👧 LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков. О правильном поведении при наследовании.
🧩 ISP (Interface-Segregation Principle) - Принцип разделения интерфейса. О том, как правильно использовать интерфейсы и абстракции.
🔃 DIP (Dependency Inversion Principle) - Принцип инверсии зависимостей. О правильной организации зависимостей на разных уровнях программы.

💬 В следующих постах периодически буду раскрывать подробнее что тут происходит.

#SOLID #Principles
Оператор if

Чем больше программирую, тем больше не люблю оператор if и стараюсь избегать его использования. Все дело в том, что из-за него вы начинаете генерировать ветки кода, что усложняет его понимание. Более того ваш код сложнее тестировать т.к. на тот же метод нужно написать больше тестов чтоб покрыть ими все возможные ветки выполнения. Например, 3 структуры if-else в теле метода уже генерируют до 8 возможных разных веток выполнения кода.

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

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

#if #SRP
Solid
Single Responsibility Principle

SRP - по-моему, один из самых простых и самых важных принципов. Каждая часть, каждый компонент системы должен отвечать за одну и только одну функциональность. Проще всего понять что система/компонент/класс удовлетворяет этому условию - это если можно дать максимально простой ответ на вопрос “что делает эта часть?” без использования “и”/”или”.

Причем в более сложных системах даже передача данных и управление поведением - это тоже разные сферы ответственности.

Основные триггеры что ваш компонент не удовлетворяет принципу SRP:
👉 При ответе на вопрос “Для чего он нужен?” вам хочется использовать частицы “и”/”или”.
👉 Вы используете оператор if в теле метода. Уже писал чуть более подробно об этом выше по хештегу #if. Само по себе ветвление означает, что что поведение запрограммировано с условием “или”.
👉 Вы передаете туда булеву переменную. Использование булевой переменной в качестве параметра является антипаттерном, т.к. уже подразумевает, что она будет использоваться в операторе if или в комбинации с другими переменными. В общем - в очередной раз появляются условности и ветки.

#if #SRP
sOlid

OCP или Open-Closed Principle довольно интересная штука. На моей практике этот принцип в целом довольно редко применяется. Возможно это связано с довольно быстрым современным миром и быстро меняющимися требованиями в agile-процессах. Тем не менее умственными упражнениями такое вполне достижимо и в реальной разработке можно (и нужно) к этому стремиться.
👉 OCP - это принцип при котором классы закрыты для изменений, но открыты для расширений.
💥 Итак, идея вот в чем. Представьте что архитектура и код в вашем проекте имеют такое свойство, что вы не можете никогда менять старый код ради нового функционала - только писать новое поведение, новые классы и т.д. Разумеется, ради исправления реальных багов, старый код можно править. А ради изменения поведения каких то классов вам нужно будет заново имплементировать какой-либо интерфейс и написать это поведение с нуля. К чему это приведет? Это приведет к тому что весь код работающий в вашем проекте будет без багов и проблем (разумеется - если ваши интерфейсы протестированы).
☝️ Более того, стремление к реализации такого принципа приведет к более лаконичной и аккуратной архитектуре - представьте, что перед стартом задачи вам скажут, что после релиза вы не сможете изменять существующие строки в классах проекта, а только дописывать новые методы и классы. Вы сразу более активно начнете пользоваться интерфейсами, абстракциями, сделаете ваши классы низкосвязанными - ведь вам не захочется в будущем переписывать весь проект ради реализации новой прихоти менеджера из-за очень высокой связности классов внутри проекта.
🧠 Попробуйте взглянуть на вашу последнюю задачу или реализованный модуль с точки зрения OCP - сможете ли вы изменить поведение части бизнес-логики не внося изменения в основные файлы? Сможете ли реализовать дополнительную функциональность не добавляя IF-ы, а лишь только добавляя новые методы и классы? В следующей задаче попробуйте найти решение такое, чтоб любое будущее изменение функциональности требовало вносить минимальные изменения в существующие классы.

#SOLID #Principles #OCP
soLid

LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков.
Меня лично всегда “конфьюзило” это неочевидное название принципа. Но - “так исторически сложилось”. Итак, о чем же он?
Он про наследование - в основном он призывает нас к тому, чтоб мы организовывали наш код таким образом, что в каком-либо месте подстановка одного объекта вместо объекта другого класса, но имплементирующего тот же интерфейс, - не приводило бы к изменению поведения методов где эти эти объекты используются. Иными словами - вызывающие методы не должны ничего знать о конкретных реализациях используемых ими интерфейсов и уж тем более как-то изменять свое поведение в зависимости от того, объект какого типа они получили на входе.

Пример:
interface Animal {
String getSound();
}
class Dog implements Animal {
public String getSound() {
return "woof";
}
}
class Cat implements Animal {
public String getSound() {
return "meow";
}
}
void doSomething(Animal animal) {
String sound = animal.getSound();
if (sound.equals("woof")) {
System.out.print("Dog");
} else {
System.out.print("Cat");
}
System.out.println(" says " + sound);
}


В примере выше можно было бы заменить и проверку по звуку на, например, проверку по instanceof. В любом случае в методе doSomething после этого появляется знание о деталях реализации интерфейса. Более того так мы нарушили и принцип #OCP - теперь для добавления новой имплементации Animal нам придется и обновлять метод doSomething.



Правильно так:

interface Animal {
String getSound();
String getName();
}
class Dog implements Animal {
public String getSound() {
return "woof";
}
public String getName() {
return "Dog";
}
}
class Cat implements Animal {
public String getSound() {
return "meow";
}
public String getName() {
return "Cat";
}
}
void doSomething(Animal animal) {
System.out.println(animal.getName() + " says " + animal.getSound());
}
solId
ISP
interface segregation principle
принцип разделения интерфейсов заключается в том, что лучше иметь более узкоспециализированные интерфейсы и уже через их имплементацию реализовывать определенное поведение у конкретных классов. Разумеется смысл тут в генерации низкосвязанного кода - когда методы и модули зависимы не от больших объектов и интерфейсов, а именно от узких интерфейсов. Наверное один из самых ярких примеров - это Iterable или Comparable в базовой поставке Java. Только представьте, насколько менее удобно было бы использовать циклы или методы сравнения, будь они основаны на более толстых интерфейсах или даже отдельных реализациях. Например, насколько сложнее стала бы наша жизнь при необходимости использовать в циклах только наследников класса Collection.
Любопытная деталь в том, что мы достаточно редко анализируем альтернативно возможные реализации нашего кода/модуля потому что в целом мы всегда можем справиться с архитектурными недостатками. Но стоит один раз переписать модуль сделав акцент на ISP как становятся понятны плюсы. Особенно если мы хотим вынести кусок модуля в виде библиотеки. Именно в процессах, критичных к низкой связности, и чувствуется огромный потенциал подходов основанных на правильном использовании интерфейсов.

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

Сейчас я веду несколько лекций на одном из курсов повышения квалификации программистов. Так вот, готовясь к лекции по паттернам проектирования у меня появилась одна интересная мысль.

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

И с паттернами в разработке та же история, - это очень мощные инструменты в руках разработчика, но непонимание зачем они нужны и какие проблемы решают ведут к тому что инструменты используются неверно. В последние пару месяцев я собеседовал пару десятков человек уровня Junior/middle, и только половина из них хорошо отвечает на вопрос "какую боль или проблему решает этот инструмент?".

Поэтому моя лекция, изначально называвшая "паттерны", превратилась в лекцию "паттерны и чистый код", причем про Clean Code там 80% материала, а про паттерны - оставшиеся крохи. Потому что именно в этом цель применения паттернов - сделать код читабельным, тестируемым, менее подверженным багам и т.д.

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

Интересный эффект попыток применить принципы Clean Code заключаются в том, что инструменты (т.е. паттерны) вы можете переизобрести заново самостоятельно, но уже с очень глубоким пониманием концепций их работы и проблем, которые они могут решить.
https://habr.com/ru/post/521062/

Вчера написали пост на хабр про программу Ноль Смертей (Vision Zero), которой в России занимаются пока что активисты. Я в этой истории немного учавствую в качеству разработчика телеграм бота для репортов аварий. Если кому-то вдруг хочется поучавствовать в чем-то опенсорс, социальном и на котлине одновременно - то welcome https://github.com/asundukov/crash_map - там пока не добавлены issues, но идейки как доработать конечно уже есть.
year++ ;)
У меня новая фраза-фаворит с последнего рабочего митинга (да-да, некоторые уже работают):

"It's double broken"