Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save pysoftware/6d241fac557075e7aec075f9c988ec62 to your computer and use it in GitHub Desktop.
Save pysoftware/6d241fac557075e7aec075f9c988ec62 to your computer and use it in GitHub Desktop.
Целеполагание
Например, тебе дали таск, где нужно пофиксить какую-то незначительную проблему,
НО гуляя по модулю, вдруг, ты заметил огромную проблему в производительности/ архитектуре и, ествественно,
ты захотел исправь этот код - сделать его идеальным
Что делать в таком случае? Перед тем как садиться делать эти "улучшения" - задай себе ряд вопросов:
1) Решена ли моя основная задача?
2) Насколько важно сейчас заниматься этими "улучшениями" (можно так же доложить о проблеме ТЛ или менедержеру, чтобы посоветоваться)?
Нужно понимать для чего ты делаешь эти улучшения и кому они будут полезны
2.1) Надо ли заниматься этими "улучшениями" именно тебе?
Ты можешь не знать некоторых тонкостей кода модуля и потратишь в разы больше времени, чем ожидал, что негативно скажется на твоей общей
производительности
3) Сколько, примерно, времени займет этот фикс?
4) Какие объективные метрики, что этот код плохой? Как ты измеришь, что твой фикс стал лучше?
Например, проблему в производительности алгоритма можно измерить по времени выполнения и сравнить
5) Код субъективен. (??? дописать)
Выгорание
Даже если ты находишься на должности джуна и не успеваешь сделать какую-то таску к концу спринта/ релиза -
НЕЛЬЗЯ убиваться, чтоб закрыть этот таск, если тебе не хватает времени
Обычно все проблемы решаемы и можно просто договориться подвинуть этот таск на след. спринт/ релиз
Если ты начнешь тратить излишнее время на этот таск - сидеть по 12 часов несколько дней, то со временем ты устанешь,
и твоя продуктивность (средняя производительность) упадет, что негативно скажется для всех:
1) Для начальства
Т.к. у тебя упала твоя средняя производительность, то теперь сложно оценить когда ты сможешь сдать даже самый легкий таск
2) Для тебя
Т.к. у тебя упала производительность, теперь тебе самому сложно оценить сколько времени займет выполнение одного таска
Появится психологический аспект, что что-то идет не так и ты начнешь угнетать самого себя, что, естественно, ещё хуже скажется на тебе
Работа с кодовой базой
Код это не книга. Нужно привязывать чтение кода только к конкретной задаче.
Cohesion
1) Functional cohesion
Есть класс с полями и каждый метод этого класса завазян на этих полях (полностью или частично), что делает этот класс трудноразделяемым
2) Cohesion последовательности
void saveUser() {
User user = UserFactory.create("Dima");
DB.save(user);
}
3) Cohesion коммуникации
Два элемента(метода) обрабатывают одни и те же данные, но каждый в своей зоне отвественности
User user = new User()
userService.register(user)
adminService.notifyUserCreated(user)
4) Procedural cohesion
Два элемента (метода) должны быть вызваны в определенном порядке, иначе алгоритм не работает
user.save()
transaction.commit()
5) Time cohesion
Несвязанные элементы должны быть вызваны в одно и тоже время
Например, стартап фреймворка, где создаются разные компоненты системы (DI container, DB, etc.)
6) Logical cohesion
Пакет содержит функции связанные между собой логически, но не имеющие общих частей кода
Эти функции будут исполняться над однми и теми же данными, но не будут зависить друг от друга
Пример: утильные классы, отдельные пакеты валидации/ сервисов/ репозиториев
7) Randomly cohesion
Несвязанные элементы в одном пакете/ классе
Пример ApacheCommons (разношерстный функционал выполнящий работу и над строками и над массивами и тп)
Copuling
Это мера независимости элемента/ класса/ модуля от других элементов
Измерение [0..1]
0 модули независмы (модуль никто не использует и он сам никого не использует)
1 модули тесносвязаны друг с другом
1) Data coupling
Разделение метода на атомарные части
changeNumber(42)
2) Stamp coupling
Из одного модуля в другой передается определенная структура (DTO (Response f.e.))
class Response { ... }
void handleResponse() {
Response response = new Response(...);
checkResponse(response); <-----------
}
3) Control coupling
Один модуль контролирует поток исполнения другого (например, флагами)
Проблема:
class Database {
void save(boolean validate) {
if (validate) {
validator.validate()
}
save();
}
}
Как решить: разделить метод на два метода (Data coupling)
void save() {
validator.validate();
save();
}
void saveWithoutValidation() {
save();
}
4) External coupling
Два модуля используют кого-то третьего для обмена данными (f.e. Singleton)
OrderService вызывает синглтон OrdersEventBus.orderCreated(order) (паралелльно)
Сложно тестировать
Иногда без него не обойтись, но если есть возможность, то лучше избежать его
5) Common coupling
Проблема:
Два разных по функционалу модуля используют одну и ту же модель данных: https://ibb.co/GQJ1cxq
При изменении DTO придется рефакторить свазу два модуля
Так же нарушется инкапсуляция DTO т.к. один из модулей не должен знать о каких-либо промежуточных данных
Решение:
Разделить DTO на два класса с инкапсулированными данными.
Первый модуль будет использовать оригинальный DTO, а второй специально предназначенный ему.
Connascence of name (Static) (Идет от хорошо (Static) к плохому (Dynamic))
1) Connascence of name
Один модуль знает о другом, только какой метод можно вызвать
db.openTransaction()
2) Connascence of type
Один модуль знает о типах другого (о типах аргументов f.e.)
user.setBirtdate("1-12-2000")
user.setBirtdate(new Date().now())
3) Connascence of meaning
Оба модуля договариваются пользоваться одним и тем же атрибутом данных (например номер банковской карты)
Например, два модуля договариваются какой тип данных будет возвращаться при вызове определенного метода
(например, вызов репозитория - если сущность не найдена выбросить ексепшн или нулл)
4) Connascene of position
ex.convert("21.65", "USD", "EUR"); <---- Можно перепутать аргументы функции
Лучше использовать
Money amountOfMoney = new Money("20.65", Currency.USD);
ex.convert(amountOfMoney, Currency.EUR);
Так же можно использовать вложенные анонимные классы, заменяя простые типы данных
5) Connascene of algorithm
Один модуль шифрует сообщение, а другой должен его расшифровать
Малейшее изменение алгоритма, влечет за собой поломку приложения из-за связанности
Connascene (Dynamic)
6) Execution order connascence
Клиент обязан знать последовательность выполнения действий для достижения цели
Email email = new Email();
email.setSender("mail");
email.send() <------------ письмо отрпавленно без subject
email.setSubject("new mail");
Если нужно показать, что последовательность действий важна,
то нужно сделать результат вызова первой функции должен быть аргументом второй
7) Timing connascence
tcpConnection.connect("192.168.122.14", 5000); // async call
tcpConnection.send(package); <----- соединение может быть не установлено к этому моменту
Решение:
Connection connection = new Connection("192.168.122.14", 5000);
EstablishedConnection ec = connection.connect();
ec.send(package);
class Connection {
...
void connect() {
// connection
return new EstablishedConnection(this);
}
}
class EstablishedConnection {
...
void send(Package package) {
...
}
}
8) Value connascence
При необходимости изменить одно значение, нужно изменить и другое
Article article = new Article("Name of article");
// publish article
article.publishDate = new Date().now();
article.status = Status.Published
Решение:
Article article = new Article("Name of article");
// publish article
article.publishNow();
// or
article.publishAt(new Date("19-02-2000"));
9) Identity connascence
Два модуля зависимы от одного интерфейса
Проблема в том, что в один момент времени один модуль получит одну реализацию, а второй другую, что вызовет рассинхрон в данных
Решение:
Объединить два модуля в один (Аркестратор). Теперь всегда будет лишь один модуль, который будет иметь одну реализацию.
HOW TO USE CONNASCENCE?
1) Конвертация динамической связности в статическую
2) Минимазация статической части
3) Сильная связность модулей опасней, чем эта же связь внутри модуля. Например, connascence of meaning, когда два модуля имеют договор
об одной константе. Возможно, стоит объединить эти модули или вынести константу в 3й модуль.
Советы от создателя connascence:
1) Минимизруйте общий уровень связности в системе, путем выделения инкапсулированных модулей.
2) Минимизируйте связность на границах пересечений модулей (?)
3) Снижайте степень связности в пределах модулей
Советы по коду:
1) В конструкторе класса должно исполняться ТОЛЬКО присваивание
Преимущество такого подхода заключается в отложенной инциализации необходимой логики.
Если бы в классе Cash в конструторе сразу вызывался Integer.parseint(this.source);,
иногда в случае ошибок или ненужности использования класса, была бы выполнена лишняя работа.
classs Cash {
private Number dollars;
Cash(String dlr) {
this.dollars = new StringAsinteger(dlr);
}
}
class stringAsinteger implements Number {
private String source;
StringAsinteger(String src) {
this.source = src;
}
int intValue() {
return Integer.parseint(this.source);
}
}
2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment