Re[12]: Интерфейсы и реализация
От: Mystic Artifact  
Дата: 29.07.20 21:13
Оценка:
Здравствуйте, Sharov, Вы писали:

S>>>Новички в DI не полезут.

MA>> У новичков нет проблем с DI — они его используют в полный рост, даже не зная как оно называется. Да, куча примеров, предлагают делать интерфейсы, но любой нормальный IoC контейнер может работать с конкретными типами, вдобавок IoC-контейнер — не что иное, как динамически-конфигурируемая фабрика. Несложно понять, что оно нужно далеко не всегда. И даже асп.нет приложении если ты хочешь per-request инстанцирование — интерфейс не нужен.
S>Интерфейс нужен с прицелом на юнит тестирование.

Боже. Я ответил на что-то другое в предыдушем сообщении. Удел новичков — учиться писать хороший / самодостаточный код. Я всегда и часто себя ощущаю новичком, потому что в процессе написания / принятия решения приходится делать микро исследования. Но новичку — топ задача — написать самодостаточный код (работающий, соответствующий требованиям). Рефлексы писать "тестируемый" код — это годы никому не нужных тренировок под один из псевдо-стандартов. Никто и никогда не сможет доказать такими способами тестирования, что код новичка который работает в 100х быстрее, хуже чем тот который как бэ тестируемый, просто ввиду того что нет инжекшн поинтов. На самом деле это возможно доказать или опровергнуть — но потребуется иной подход. Есть вполне конкретные кейсы таких ситуаций: JIT генерирует трудноуловимый неправильный код сопровождающийся рандомными исключениями. Можно просто поискать на гитхабе. Решения, кроме регресс тестов нет, но регрессы появятся только после инциндентов, а
на предложения внедрить "интерфейсы с приметой на тестирование" — будете посланы любым инженером на другой конец света.

Очень грубая аналогия — летать на самолете с заранее раскрывшимся парашютом, с прицелом на то, что он может не раскрыться.
Re: Интерфейсы и реализация
От: rosencrantz США  
Дата: 02.09.20 18:41
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Чем руководствуетесь, принимая решение выделять или не выделять интерфейс из класса, т.е. нужно ли разделить интерфейс и реализацию?


Б>Когда имеется несколько реализация — понятно, интерфейс обычно выделяют.

Б>Но если реализация только одна, для каких классов выделяете интерфейсы, а для каких нет?

Б>P.S. Возможно, ответ сильно зависит от используемого языка. По возможности, укажите используемый язык.


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

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

1. Заточить решение под эту конкретную ситуацию.
2. Оставить решение общим, и просто, да, использовать его всего 1 раз для этой конкретной ситуации.

Для п.2 интерфейс используется как граница между "вообще решением" и "решением для конкретной ситуации". Например задача — импортировать юзеров из CSV файла — в SQL базу.

interface UserHandler {
  void handleUser(User user);
}

class UserCsvReader {
  void readAllUsers(UserHandler userHandler) {
    ...
  }
}

class BatchInserter<TRow> {
  BatchInserter(String sql, int batchSize) {...}

  void insert(TRow row) {
    if (batch.size < batchSize) {
      batch.add(row);
    } else {
      connection.batchUpdate(sql, batch);
      batch.clear();
    }    
  }
}

class BatchInsertingUserHandler implements UserHandler {
  BatchInsertingUserHandler(BatchInserter<UserRow> batchInserter) {}

  void handleUser(User user) {
    UserRow r = makeRowFromUser(user);
    batchInserter.insert(r);
  }
}

BatchInserter<UserRow> batchInserter = new BatchInserter("insert into Users(...)");
BatchInsertingUserHandler userHandler = new BatchInsertingUserHandler(batchInserter);
UserCsvReader reader = new UsersCsvReader();
reader.readAllUsers(userHandler);


Здесь интерфейс UserHandler используется чтобы отрезать "читание users CSV" от "писания в БД". Интерфейс тут позволяет показать, что вот этот код он конкретно про читание. Он используется при импорте юзеров, но это не сам импорт, а один из инструментов, которые используются импортом.

Если интерфейс выкинуть и оставить только сам BatchInsertingUserHandler, тут возникает много неясностей по поводу как кого переименовать, чтобы не получилось, что холодильник знает о существовании духовки, потому что они оба на кухне.
Re: Интерфейсы и реализация
От: AlexRK  
Дата: 02.09.20 18:59
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Чем руководствуетесь, принимая решение выделять или не выделять интерфейс из класса, т.е. нужно ли разделить интерфейс и реализацию?

Б>Когда имеется несколько реализация — понятно, интерфейс обычно выделяют.
Б>Но если реализация только одна, для каких классов выделяете интерфейсы, а для каких нет?

Не делаю интерфейсов, если это не надо для какой-то конкретной цели (чтобы абстрагироваться без наследования). В 99% случаев мне это не надо. Тестов не пишу.

Б>P.S. Возможно, ответ сильно зависит от используемого языка. По возможности, укажите используемый язык.


C#.
Re[2]: Интерфейсы и реализация
От: · Великобритания  
Дата: 02.09.20 20:11
Оценка: 1 (1)
Здравствуйте, rosencrantz, Вы писали:

R>Если интерфейс выкинуть и оставить только сам BatchInsertingUserHandler, тут возникает много неясностей

Я не вижу никаких неясностей. Что плохого с именем "UserHandler" для этого класса? Зачем этот префикс BatchInserting?

class UserCsvReader {
  void readAllUsers(UserHandler userHandler) {
    ...
  }
}

class BatchInserter<TRow> {
  BatchInserter(String sql, int batchSize) {...}

  void insert(TRow row) {
    if (batch.size < batchSize) {
      batch.add(row);
    } else {
      connection.batchUpdate(sql, batch);
      batch.clear();
    }    
  }
}

class UserHandler {
  UserHandler(BatchInserter<UserRow> batchInserter) {}

  void handleUser(User user) {
    UserRow r = makeRowFromUser(user);
    batchInserter.insert(r);
  }
}

BatchInserter<UserRow> batchInserter = new BatchInserter("insert into Users(...)");
UserHandler userHandler = new UserHandler(batchInserter);
UserCsvReader reader = new UsersCsvReader();
reader.readAllUsers(userHandler);

И что не так?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 02.09.2020 20:18 · . Предыдущая версия .
Re[3]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 02.09.20 21:20
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>Если интерфейс выкинуть и оставить только сам BatchInsertingUserHandler, тут возникает много неясностей

·>Я не вижу никаких неясностей. Что плохого с именем "UserHandler" для этого класса? Зачем этот префикс BatchInserting?

Там перед кодом дофига написано по поводу мотивации

1. Можно 3 модуля: csv, запись, импорт. Импорт использует первые два.
2. Можно 1 модуль: импорт. Сам умеет csv и запись.
3. Можно эту фичу оформить как часть уже существующего модуля и вообще в один метод всё свернуть.

Я не всегда хочу п.1, но когда я хочу, тогда я делаю "интерфейс с одной реализацией". Мой пример кода — это п.1, ваш — это п.2. О чём мы тут спорим?
Re[4]: Интерфейсы и реализация
От: · Великобритания  
Дата: 02.09.20 22:04
Оценка:
Здравствуйте, rosencrantz, Вы писали:


R>>>Если интерфейс выкинуть и оставить только сам BatchInsertingUserHandler, тут возникает много неясностей

R>·>Я не вижу никаких неясностей. Что плохого с именем "UserHandler" для этого класса? Зачем этот префикс BatchInserting?

R>Там перед кодом дофига написано по поводу мотивации

Я не очень понимаю эту мотивацию, вот и задаю вопросы.

R>1. Можно 3 модуля: csv, запись, импорт. Импорт использует первые два.

R>2. Можно 1 модуль: импорт. Сам умеет csv и запись.
R>3. Можно эту фичу оформить как часть уже существующего модуля и вообще в один метод всё свернуть.

R>Я не всегда хочу п.1, но когда я хочу, тогда я делаю "интерфейс с одной реализацией". Мой пример кода — это п.1, ваш — это п.2. О чём мы тут спорим?

Я пытаюсь выяснить что скрывается за словом "хочу". Ведь должны быть какие то более-менее рациональные критерии выбора. Это и есть вопрос топикстартера.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 03.09.20 03:39
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>Там перед кодом дофига написано по поводу мотивации

·>Я не очень понимаю эту мотивацию, вот и задаю вопросы.

R>>1. Можно 3 модуля: csv, запись, импорт. Импорт использует первые два.

R>>2. Можно 1 модуль: импорт. Сам умеет csv и запись.
R>>3. Можно эту фичу оформить как часть уже существующего модуля и вообще в один метод всё свернуть.

R>>Я не всегда хочу п.1, но когда я хочу, тогда я делаю "интерфейс с одной реализацией". Мой пример кода — это п.1, ваш — это п.2. О чём мы тут спорим?

·>Я пытаюсь выяснить что скрывается за словом "хочу". Ведь должны быть какие то более-менее рациональные критерии выбора. Это и есть вопрос топикстартера.

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

Хотим мы один модуль или несколько — тут по-моему всё сильно зависит от ментальных моделей и предпочтений. Лезет задачу в голову легко, или со скрипом, или вообще не лезет. Кто-то думает — "мне дают какие-то записи, я группирую их по 100 и делаю batch insert" и ему комфортно. Кто-то думает — "я читаю из csv по 100 строчек и делаю batch insert" и ему комфортно. Кто-то думает — "я получаю какие-то записи и как-то их обрабатываю" (таких обычно бьют, да? ). Модули по-моему откуда-то отсюда вытекают (как и coupling/cohesion, SRP, правило 5+/-2 и прочие всем известные уловки).
Отредактировано 03.09.2020 3:41 rosencrantz . Предыдущая версия . Еще …
Отредактировано 03.09.2020 3:40 rosencrantz . Предыдущая версия .
Re[6]: Интерфейсы и реализация
От: · Великобритания  
Дата: 03.09.20 07:20
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>>>Я не всегда хочу п.1, но когда я хочу, тогда я делаю "интерфейс с одной реализацией". Мой пример кода — это п.1, ваш — это п.2. О чём мы тут спорим?

R>·>Я пытаюсь выяснить что скрывается за словом "хочу". Ведь должны быть какие то более-менее рациональные критерии выбора. Это и есть вопрос топикстартера.

R>Тс задал вопрос про классы, поэтому я отвечаю про классы. Нужен интерфейс или не нужен (у меня) диктуется тем, хотим мы выделить модуль или нет. Если решение состоит из двух (или больше) модулей, интерфейсы нужны, даже если реализация всего одна. Если решение состоит из одного модуля, интерфейсы не нужны. Один и тот же набор классов можно воспринимать и как один модуль, и как несколько.

Модуль это в смысле jar/dll? Да, там без интерфейса в принцпипе не получится. Я об этом уже писал в самом первом моём сообщении. Но у модуля довольно много накладных расходов и они должны быть меньше, чем выгода от использования модулей.

R>Хотим мы один модуль или несколько — тут по-моему всё сильно зависит от ментальных моделей и предпочтений. Лезет задачу в голову легко, или со скрипом, или вообще не лезет. Кто-то думает — "мне дают какие-то записи, я группирую их по 100 и делаю batch insert" и ему комфортно. Кто-то думает — "я читаю из csv по 100 строчек и делаю batch insert" и ему комфортно. Кто-то думает — "я получаю какие-то записи и как-то их обрабатываю" (таких обычно бьют, да? ). Модули по-моему откуда-то отсюда вытекают (как и coupling/cohesion, SRP, правило 5+/-2 и прочие всем известные уловки).

Тоже опять какие-то субъективные критерии, желание левой пятки...
Модули нужны таки для переиспользования и ограничения зависимостей. Например, чтобы в модуле работы с файловой системой не было доступа к сети. Ещё для организации процесса разработки, например, разработка разными командами или для повышения эффективности процесса билда/тестирования/етс.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 03.09.20 13:48
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>Тс задал вопрос про классы, поэтому я отвечаю про классы. Нужен интерфейс или не нужен (у меня) диктуется тем, хотим мы выделить модуль или нет. Если решение состоит из двух (или больше) модулей, интерфейсы нужны, даже если реализация всего одна. Если решение состоит из одного модуля, интерфейсы не нужны. Один и тот же набор классов можно воспринимать и как один модуль, и как несколько.

·>Модуль это в смысле jar/dll? Да, там без интерфейса в принцпипе не получится. Я об этом уже писал в самом первом моём сообщении. Но у модуля довольно много накладных расходов и они должны быть меньше, чем выгода от использования модулей.

Не, модуль в смысле — совокупность кода, решающего осмысленную (осмыслимую) задачу (как в "модульное тестирование"). Это может быть 1 класс — какой-нибудь StringBuilder. Может быть несколько — CsvReader и CsvRow.

R>>Хотим мы один модуль или несколько — тут по-моему всё сильно зависит от ментальных моделей и предпочтений. Лезет задачу в голову легко, или со скрипом, или вообще не лезет. Кто-то думает — "мне дают какие-то записи, я группирую их по 100 и делаю batch insert" и ему комфортно. Кто-то думает — "я читаю из csv по 100 строчек и делаю batch insert" и ему комфортно. Кто-то думает — "я получаю какие-то записи и как-то их обрабатываю" (таких обычно бьют, да? ). Модули по-моему откуда-то отсюда вытекают (как и coupling/cohesion, SRP, правило 5+/-2 и прочие всем известные уловки).

·>Тоже опять какие-то субъективные критерии, желание левой пятки...



·>Модули нужны таки для переиспользования и ограничения зависимостей. Например, чтобы в модуле работы с файловой системой не было доступа к сети. Ещё для организации процесса разработки, например, разработка разными командами или для повышения эффективности процесса билда/тестирования/етс.


Терминологическая путаница просто. Я про модули на уровне написания кода, а вы про библиотеки.
Re[6]: Интерфейсы и реализация
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.09.20 15:52
Оценка: +1 :)
Здравствуйте, rosencrantz, Вы писали:

R>Тс задал вопрос про классы, поэтому я отвечаю про классы. Нужен интерфейс или не нужен (у меня) диктуется тем, хотим мы выделить модуль или нет.




Видимо, предлагается проголосовать?
Re[7]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 03.09.20 16:03
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, rosencrantz, Вы писали:


R>>Тс задал вопрос про классы, поэтому я отвечаю про классы. Нужен интерфейс или не нужен (у меня) диктуется тем, хотим мы выделить модуль или нет.


S>


S>Видимо, предлагается проголосовать?


А по делу есть что сказать?
Re[8]: Интерфейсы и реализация
От: · Великобритания  
Дата: 03.09.20 17:43
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>·>Модуль это в смысле jar/dll? Да, там без интерфейса в принцпипе не получится. Я об этом уже писал в самом первом моём сообщении. Но у модуля довольно много накладных расходов и они должны быть меньше, чем выгода от использования модулей.

R>Не, модуль в смысле — совокупность кода, решающего осмысленную (осмыслимую) задачу (как в "модульное тестирование"). Это может быть 1 класс — какой-нибудь StringBuilder. Может быть несколько — CsvReader и CsvRow.
Ок. Вот тогда твой пример с UserHandler непонятен. Я так и не понял накой там interface UserHandler, чем плох просто class UserHandler.
И уж тем более кошмарик BatchInsertingUserHandler, как будто ты имя класса так придумал.
Я для сравнения привёл код без интерфейса — по каким критериям он хуже?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 03.09.20 19:15
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>·>Модуль это в смысле jar/dll? Да, там без интерфейса в принцпипе не получится. Я об этом уже писал в самом первом моём сообщении. Но у модуля довольно много накладных расходов и они должны быть меньше, чем выгода от использования модулей.

R>>Не, модуль в смысле — совокупность кода, решающего осмысленную (осмыслимую) задачу (как в "модульное тестирование"). Это может быть 1 класс — какой-нибудь StringBuilder. Может быть несколько — CsvReader и CsvRow.
·>Ок. Вот тогда твой пример с UserHandler непонятен. Я так и не понял накой там interface UserHandler, чем плох просто class UserHandler.
·>И уж тем более кошмарик BatchInsertingUserHandler, как будто ты имя класса так придумал.
·>Я для сравнения привёл код без интерфейса — по каким критериям он хуже?

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

Вот сокращённая версия моего кода:

// модуль 1 - "чтение CSV"
interface UserHandler {...}
class UserCsvReader {...}
// конец модуля 1

// модуль 2 - "запись в базу батчами"
class BatchInserter<TRow> {...}
// конец модуля 2

// модуль 3 - "импорт" (использует модуль "чтение CSV" и модуль "запись в базу батчами")
class BatchInsertingUserHandler implements UserHandler {
  BatchInsertingUserHandler(BatchInserter<UserRow> batchInserter) {...}
}

BatchInserter<UserRow> batchInserter = new BatchInserter("insert into Users(...)");
BatchInsertingUserHandler userHandler = new BatchInsertingUserHandler(batchInserter);
UserCsvReader reader = new UsersCsvReader();
reader.readAllUsers(userHandler);
// конец модуля 3


Интерфейс UserHandler здесь нужен для того, чтобы показать границу между модулем 1 (как мы читаем CSV) и модулем 3 (когда мы читаем CSV, что мы с этим делаем). Модуль 1 в этом случае именно вполне самостоятельный модуль. Его можно без изменений переиспользовать для например написания конвертора из CSV — в XML. Но это не очень важно. Важно что самодостаточная концепция изолирована от остального мира То же самое, что ваша иллюстрация про "файловая система не должна знать про сеть" — у меня "читалка csv не должна знать про писалку в бд", просто масштаб другой.

В вашей версии если UserHandler превращается в BatchInsertingUserHandler, модуль 1 исчезает и его содержимое становится частью модуля 3. Конвертор CSV->XML вы уже не напишете без правок кода, но такой цели и не было. Но вообще чтение CSV у вас теперь гвоздями прибито к вставке в базу.
Re[10]: Интерфейсы и реализация
От: · Великобритания  
Дата: 04.09.20 09:49
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>·>Ок. Вот тогда твой пример с UserHandler непонятен. Я так и не понял накой там interface UserHandler, чем плох просто class UserHandler.

R>·>И уж тем более кошмарик BatchInsertingUserHandler, как будто ты имя класса так придумал.
R>·>Я для сравнения привёл код без интерфейса — по каким критериям он хуже?

R>Он не обязательно хуже, он просто не обладает теми свойствами, которыми обладает мой вариант. Плохо это или хорошо — я ж как раз пытаюсь донести — зависит от восприятия автора/читателя.

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

R>Вот сокращённая версия моего кода:

// модуль 3 - "импорт" (использует модуль "чтение CSV" и модуль "запись в базу батчами")
class BatchInsertingUserHandler implements UserHandler {
  BatchInsertingUserHandler(BatchInserter<UserRow> batchInserter) {...}
}

 --- вот здесь явно видна ещё граница между модулями. "модуль импорт" и "модуль сборки конечного приложения"
 --- т.к. это явно просто wiring code, composition root.

BatchInserter<UserRow> batchInserter = new BatchInserter("insert into Users(...)");
BatchInsertingUserHandler userHandler = new BatchInsertingUserHandler(batchInserter);
UserCsvReader reader = new UsersCsvReader();
reader.readAllUsers(userHandler);
// конец модуля 3


R>Интерфейс UserHandler здесь нужен для того, чтобы показать границу между модулем 1 (как мы читаем CSV) и модулем 3 (когда мы читаем CSV, что мы с этим делаем). Модуль 1 в этом случае именно вполне самостоятельный модуль. Его можно без изменений переиспользовать для например написания конвертора из CSV — в XML. Но это не очень важно. Важно что самодостаточная концепция изолирована от остального мира То же самое, что ваша иллюстрация про "файловая система не должна знать про сеть" — у меня "читалка csv не должна знать про писалку в бд", просто масштаб другой.

Тут я топлю за принцип YAGNI. Вот когда нам не станет хватать, что наш class UserHandler пишет батчами в бд, вот тогда мы отрефакторим код и у нас получится interface UserHandler и реализующие его class DbUserWriter, class XmlUserWriter — с не вымученными enterprisified именами, а явно продиктованными новыми появившимися требованиями.

R>В вашей версии если UserHandler превращается в BatchInsertingUserHandler, модуль 1 исчезает и его содержимое становится частью модуля 3. Конвертор CSV->XML вы уже не напишете без правок кода, но такой цели и не было. Но вообще чтение CSV у вас теперь гвоздями прибито к вставке в базу.

Модуль 1 не исчезнет, а станет состоять из только лишь класса UserCsvReader.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 04.09.20 13:49
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>·>Ок. Вот тогда твой пример с UserHandler непонятен. Я так и не понял накой там interface UserHandler, чем плох просто class UserHandler.

R>>·>И уж тем более кошмарик BatchInsertingUserHandler, как будто ты имя класса так придумал.
R>>·>Я для сравнения привёл код без интерфейса — по каким критериям он хуже?

R>>Он не обязательно хуже, он просто не обладает теми свойствами, которыми обладает мой вариант. Плохо это или хорошо — я ж как раз пытаюсь донести — зависит от восприятия автора/читателя.

·>Ок. Каким образом в коде выражается это разбиение на модули? Ну т.е. представь себе ты написал код, закоммитил, я открываю твой код и я там увижу эти модули? Как читатель узнает твоё авторское восприятие этого кода?

Ну серьёзно? "Ну т.е. представь себе ты написал код, закоммитил, <скип> Как читатель узнает твоё авторское восприятие этого кода?" — про это пишутся сотни книжек и ведутся регулярные срачи на рсдн. Какой ответ вы ожидаете услышать?

R>>Интерфейс UserHandler здесь нужен для того, чтобы показать границу между модулем 1 (как мы читаем CSV) и модулем 3 (когда мы читаем CSV, что мы с этим делаем). Модуль 1 в этом случае именно вполне самостоятельный модуль. Его можно без изменений переиспользовать для например написания конвертора из CSV — в XML. Но это не очень важно. Важно что самодостаточная концепция изолирована от остального мира То же самое, что ваша иллюстрация про "файловая система не должна знать про сеть" — у меня "читалка csv не должна знать про писалку в бд", просто масштаб другой.

·>Тут я топлю за принцип YAGNI.

А не вкусовщина ли это?

·>Вот когда нам не станет хватать, что наш class UserHandler пишет батчами в бд, вот тогда мы отрефакторим код и у нас получится interface UserHandler и реализующие его class DbUserWriter, class XmlUserWriter — с не вымученными enterprisified именами, а явно продиктованными новыми появившимися требованиями.


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

Можно провести аналогию с поясняющей переменной:

if (person.age >= 21) {
  ...
}


Всё тут в порядке? YAGNI не чешется?

bool isAllowedToDrinkBear = person.age >= 21;
if (isAllowedToDrinkBear) {
  ...
}


Нужна поясняющая переменная? Или YAGNI и потом отрефакторим? Вносит она проблемы? Увеличивает сложность экспоненциально? Что насчёт поясняющей функции?

if (isAllowedToDrinkBear(person)) {
  ...
}


Тут как? YAGNI? Что насчёт выноса этой функции в отдельный класс?

if (bearDrinkingDecisionMaker.isAllowedToDrinkBear(person)) {
  ...
}


Во всех случаях (кроме первого) появление имени "isAllowedToDrinkBear" — это тот самый ввод интерфейса.

R>>В вашей версии если UserHandler превращается в BatchInsertingUserHandler, модуль 1 исчезает и его содержимое становится частью модуля 3. Конвертор CSV->XML вы уже не напишете без правок кода, но такой цели и не было. Но вообще чтение CSV у вас теперь гвоздями прибито к вставке в базу.

·>Модуль 1 не исчезнет, а станет состоять из только лишь класса UserCsvReader.

Это не модуль. Модуль — это когда можно провести границу. В вашем случае границу провести не получится
Re[12]: Интерфейсы и реализация
От: · Великобритания  
Дата: 04.09.20 17:20
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>>>Он не обязательно хуже, он просто не обладает теми свойствами, которыми обладает мой вариант. Плохо это или хорошо — я ж как раз пытаюсь донести — зависит от восприятия автора/читателя.

R>·>Ок. Каким образом в коде выражается это разбиение на модули? Ну т.е. представь себе ты написал код, закоммитил, я открываю твой код и я там увижу эти модули? Как читатель узнает твоё авторское восприятие этого кода?
R>Ну серьёзно? "Ну т.е. представь себе ты написал код, закоммитил, <скип> Как читатель узнает твоё авторское восприятие этого кода?" — про это пишутся сотни книжек и ведутся регулярные срачи на рсдн. Какой ответ вы ожидаете услышать?
Серьёзно. Так я и пытаюсь обратить внимание важность именно явных моментов. Скажем, твой изначальный код я понял без пояснений что там есть. А вот твои "модули" я там не увидел, а после того как ты их указал — я мысленно увидел и другие варианты разбиения. Значит это только лишь твоя субъекивная картина. Т.е. ты ради своей личной субъективной картины усложняешь код, внося туда лишние конструкции языка и запутывая читателя, т.к. нет ничего явного, что бы позволило передать авторское восприятие.

R>·>Тут я топлю за принцип YAGNI.

R>А не вкусовщина ли это?
Писать простой код — вкусовщина?

R>·>Вот когда нам не станет хватать, что наш class UserHandler пишет батчами в бд, вот тогда мы отрефакторим код и у нас получится interface UserHandler и реализующие его class DbUserWriter, class XmlUserWriter — с не вымученными enterprisified именами, а явно продиктованными новыми появившимися требованиями.

R>Я совершенно за YAGNI, но только там где противопоставляются более накрученное решение и более простое. Добавление 1 интерфейса не делает решение более сложным — ни в восприятии, ни в реализации, ни в сопровождении. Для тех, кто не сечёт фишку, решение по сложности — такое же, как и без интерфейса, для тех, кто сечёт — это "граница интерфейса, точка расширения"
В реализации сложность — как минимум у тебя появляется необходимость придумывать два имени для сущностей. BatchInsertingUserHandler — выглядит жутко.
В сопровождении — выяснить что делает handleUser — надо прыгать между местом использования между интерфейсом и классом.

R>Можно провести аналогию с поясняющей переменной:


R>
R>if (person.age >= 21) {
R>  ...
R>}
R>

R>Всё тут в порядке? YAGNI не чешется?
Тут magic number чешется как минимум. Понятно, что другие принципы тоже важны. Вот какому принципу ты следуешь, когда хочешь сделать тот интерфейс — я и хочу понять.

R>
R>bool isAllowedToDrinkBear = person.age >= 21;
R>if (isAllowedToDrinkBear) {
R>  ...
R>}
R>

R>Нужна поясняющая переменная? Или YAGNI и потом отрефакторим? Вносит она проблемы? Увеличивает сложность экспоненциально? Что насчёт поясняющей функции?
Либо так, либо "const DRINK_BEER_LEGAL_AGE = 21". Т.к. из кода совершенно непонятно какой семантикой обладает "age >= 21". То ли пиво, то ли ношение оружия, толи порно. В твоём примере с интерфейсом я неоднозначностей не заметил, так что не очень хорошая аналогия.
Кстати, медведей лучше не пить, даже в 21.

R>
R>if (isAllowedToDrinkBear(person)) {
R>  ...
R>}
R>

R>Тут как? YAGNI? Что насчёт выноса этой функции в отдельный класс?
Если код используется из разных частей кода, то имеет смысл вынести в функцию, да. А иначе, ясен пень, надо остановиться на предыдущем шаге.

R>
R>if (bearDrinkingDecisionMaker.isAllowedToDrinkBear(person)) {
R>  ...
R>}
R>

R>Во всех случаях (кроме первого) появление имени "isAllowedToDrinkBear" — это тот самый ввод интерфейса.
То же самое, для переиспользования или если isAllowedToDrinkBear имеет смысл покрыть отдельно тестами. Правда конкретно для тривиального выражения вроде "age >= 21" я бы точно не стал тестами отдельно покрывать.

R>>>В вашей версии если UserHandler превращается в BatchInsertingUserHandler, модуль 1 исчезает и его содержимое становится частью модуля 3. Конвертор CSV->XML вы уже не напишете без правок кода, но такой цели и не было. Но вообще чтение CSV у вас теперь гвоздями прибито к вставке в базу.

R>·>Модуль 1 не исчезнет, а станет состоять из только лишь класса UserCsvReader.
R>Это не модуль. Модуль — это когда можно провести границу. В вашем случае границу провести не получится
Я значит не понял принцип по которому ты проводишь границы. По-моему всё нормально проводится.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[13]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 04.09.20 21:26
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:


R>>>>Он не обязательно хуже, он просто не обладает теми свойствами, которыми обладает мой вариант. Плохо это или хорошо — я ж как раз пытаюсь донести — зависит от восприятия автора/читателя.

R>>·>Ок. Каким образом в коде выражается это разбиение на модули? Ну т.е. представь себе ты написал код, закоммитил, я открываю твой код и я там увижу эти модули? Как читатель узнает твоё авторское восприятие этого кода?
R>>Ну серьёзно? "Ну т.е. представь себе ты написал код, закоммитил, <скип> Как читатель узнает твоё авторское восприятие этого кода?" — про это пишутся сотни книжек и ведутся регулярные срачи на рсдн. Какой ответ вы ожидаете услышать?
·>Серьёзно. Так я и пытаюсь обратить внимание важность именно явных моментов. Скажем, твой изначальный код я понял без пояснений что там есть. А вот твои "модули" я там не увидел, а после того как ты их указал — я мысленно увидел и другие варианты разбиения. Значит это только лишь твоя субъекивная картина. Т.е. ты ради своей личной субъективной картины усложняешь код, внося туда лишние конструкции языка и запутывая читателя, т.к. нет ничего явного, что бы позволило передать авторское восприятие.

Именно субъективная ментальная модель автора и определяет на какие части будет порезан код, и как эти части будут взаимодействовать. Олимпиадник будет строить ментальную модель на основе своего видения важного: корректность, скорость, память, но не сопровождаемость или тестируемость. Не-олимпиадники вполне будут руководствоваться сопровождаемостью и тестируемостью, но всё равно остаётся много свободы. Если в ментальной модели автора есть самостоятельный компонент X, отрезанный от всего остального мира, автор может попытаться эту самостоятельность и отрезанность как-то показать.

Один из вариантов представления этого в коде — использование компонентом X интерфейса к внешнему миру вместо самого внешнего мира. Это частный случай https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8/%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8 — для переиспользования X в нескольких разных "мирах" не нужно делать никаких правок в самом X, нужно просто добавлять новые реализации интерфейса и подсовывать их в X. Мне не надо ждать пока меня петух в задницу клюнет, чтобы увидеть разницу между связью "чтение CSV" — "запись в БД" (её нет) и, "чтение CSV" — "запись CSV" (механизмы для (де)экранирования строк наверняка будут одни и те же — и там, и там) Вы разницу видите?

R>>·>Тут я топлю за принцип YAGNI.

R>>А не вкусовщина ли это?
·>Писать простой код — вкусовщина?

Да вы так с этим YAGNI носитесь, как будто это правда что-то. Ну кто-то предложил принцип, и дальше что? За ним нет исследований с цифрами, экспериментальных подтверждений, это просто "экспертное мнение". С этим мнением можно согласиться, можно не согласиться, можно иметь в виду, можно поспорить о границах применимости. OCP вон тоже принцип — "пишите код так, чтобы только дописывать и никогда не трогать уже написанное" — я не знаю если вы вообще его принимаете, но очевидно он у вас глубоко не на первом месте.

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

R>>·>Вот когда нам не станет хватать, что наш class UserHandler пишет батчами в бд, вот тогда мы отрефакторим код и у нас получится interface UserHandler и реализующие его class DbUserWriter, class XmlUserWriter — с не вымученными enterprisified именами, а явно продиктованными новыми появившимися требованиями.

R>>Я совершенно за YAGNI, но только там где противопоставляются более накрученное решение и более простое. Добавление 1 интерфейса не делает решение более сложным — ни в восприятии, ни в реализации, ни в сопровождении. Для тех, кто не сечёт фишку, решение по сложности — такое же, как и без интерфейса, для тех, кто сечёт — это "граница интерфейса, точка расширения"
·>В реализации сложность — как минимум у тебя появляется необходимость придумывать два имени для сущностей. BatchInsertingUserHandler — выглядит жутко.
·>В сопровождении — выяснить что делает handleUser — надо прыгать между местом использования между интерфейсом и классом.

Странно, у меня такая же BatchInsertingUserHandler — и не болит Если видел одним глазом в коде интерфейс UserHandler, все классы с таким суффиксом автоматически воспринимаются как реализации этого интерфейса. "BatchInserting" описывает чем примечательна эта конкретная реализация.

R>>>>В вашей версии если UserHandler превращается в BatchInsertingUserHandler, модуль 1 исчезает и его содержимое становится частью модуля 3. Конвертор CSV->XML вы уже не напишете без правок кода, но такой цели и не было. Но вообще чтение CSV у вас теперь гвоздями прибито к вставке в базу.

R>>·>Модуль 1 не исчезнет, а станет состоять из только лишь класса UserCsvReader.
R>>Это не модуль. Модуль — это когда можно провести границу. В вашем случае границу провести не получится
·>Я значит не понял принцип по которому ты проводишь границы. По-моему всё нормально проводится.

Ну давайте совсем в лоб. Хорошая граница — это когда код читалки CSV идёт в отдельную библиотеку usercsvreader.dll и, блин, не тянет за собой драйвер Mysql В моём понимании адекватный код пишется именно с этим ограничением в голове. В версии с интерфейсом оно будет именно так — взял и перетащил, никаких правок в коде.
Re[14]: Интерфейсы и реализация
От: · Великобритания  
Дата: 04.09.20 22:25
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>·>Серьёзно. Так я и пытаюсь обратить внимание важность именно явных моментов. Скажем, твой изначальный код я понял без пояснений что там есть. А вот твои "модули" я там не увидел, а после того как ты их указал — я мысленно увидел и другие варианты разбиения. Значит это только лишь твоя субъекивная картина. Т.е. ты ради своей личной субъективной картины усложняешь код, внося туда лишние конструкции языка и запутывая читателя, т.к. нет ничего явного, что бы позволило передать авторское восприятие.

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

R>Один из вариантов представления этого в коде — использование компонентом X интерфейса к внешнему миру вместо самого внешнего мира. Это частный случай https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8/%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8 — для переиспользования X в нескольких разных "мирах" не нужно делать никаких правок в самом X, нужно просто добавлять новые реализации интерфейса и подсовывать их в X. Мне не надо ждать пока меня петух в задницу клюнет, чтобы увидеть разницу между связью "чтение CSV" — "запись в БД" (её нет) и, "чтение CSV" — "запись CSV" (механизмы для (де)экранирования строк наверняка будут одни и те же — и там, и там) Вы разницу видите?

Нет. У тебя был код чтения csv который дёргал handleUser — и ему было по барабану что там пишется в БД. И вообще разницы не было это метод интерфейса или класса. В реализации handleUser писалась БД и было по барабану кто дёргал этот метод. Добавление интерфейса в случае ровно одной реалицаии ничего не меняет.

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

R>·>Писать простой код — вкусовщина?

R>Да вы так с этим YAGNI носитесь, как будто это правда что-то. Ну кто-то предложил принцип, и дальше что? За ним нет исследований с цифрами, экспериментальных подтверждений, это просто "экспертное мнение". С этим мнением можно согласиться, можно не согласиться, можно иметь в виду, можно поспорить о границах применимости. OCP вон тоже принцип — "пишите код так, чтобы только дописывать и никогда не трогать уже написанное" — я не знаю если вы вообще его принимаете, но очевидно он у вас глубоко не на первом месте.
Рефакторинг "class UserHandler" -> "interface UserHandler" + "class DbUserHandler" не трогает уже написанное и с OCP не конфликтует.

R>Ну и прежде чем называть код простым, поделитесь вашими критериями простоты.

При прочих равных — чем короче, тем проще. Твой код длиннее, а в остальном я разницы не вижу.

R>·>В реализации сложность — как минимум у тебя появляется необходимость придумывать два имени для сущностей. BatchInsertingUserHandler — выглядит жутко.

R>·>В сопровождении — выяснить что делает handleUser — надо прыгать между местом использования между интерфейсом и классом.
R>Странно, у меня такая же BatchInsertingUserHandler — и не болит Если видел одним глазом в коде интерфейс UserHandler, все классы с таким суффиксом автоматически воспринимаются как реализации этого интерфейса. "BatchInserting" описывает чем примечательна эта конкретная реализация.
Ок, отдельный флейм не буду начинать... именование — может быть дело вкуса, могу согласится.

R>>>·>Модуль 1 не исчезнет, а станет состоять из только лишь класса UserCsvReader.

R>>>Это не модуль. Модуль — это когда можно провести границу. В вашем случае границу провести не получится
R>·>Я значит не понял принцип по которому ты проводишь границы. По-моему всё нормально проводится.

R>Ну давайте совсем в лоб. Хорошая граница — это когда код читалки CSV идёт в отдельную библиотеку usercsvreader.dll и, блин, не тянет за собой драйвер Mysql В моём понимании адекватный код пишется именно с этим ограничением в голове.

А почему ты именно тут границу ставишь? Может лучше граница это когда код идёт в отдельный асинхронный скалируемый микросервис? Ну json там, калбеки, ретраи, таймауты, рекавери, балансинг... Библиотеки нынче уже не модно.
Или всё-таки лучше придерживаться необходимого минимума? "Всё должно быть изложено так просто, как только возможно, но не проще".

R> В версии с интерфейсом оно будет именно так — взял и перетащил, никаких правок в коде.

А ты сделай diff между твоим
Автор: rosencrantz
Дата: 02.09.20
кодом и моим
Автор: ·
Дата: 02.09.20
. И заметь — реальных правок нет никаких, просто удалены лишние символы.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[15]: Интерфейсы и реализация
От: rosencrantz США  
Дата: 04.09.20 23:43
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, rosencrantz, Вы писали:



R>>Именно субъективная ментальная модель автора и определяет на какие части будет порезан код, и как эти части будут взаимодействовать. Олимпиадник будет строить ментальную модель на основе своего видения важного: корректность, скорость, память, но не сопровождаемость или тестируемость. Не-олимпиадники вполне будут руководствоваться сопровождаемостью и тестируемостью, но всё равно остаётся много свободы. Если в ментальной модели автора есть самостоятельный компонент X, отрезанный от всего остального мира, автор может попытаться эту самостоятельность и отрезанность как-то показать.

·>Ну олимпиадники это не в тему, по-моему было очевидно, что я говорю в контексте промышленного программирования, когда цель — профессионально написанный код,

Это у вас такая цель? Что это вообще такое — "профессионально написанный код" расскажете? У меня такой цели нет. В моей реальности мы все принимаем технические решения и получаем за это зарплату. Что там профессиональный код, что непрофессиональный — это каждый сам себе перед зеркалом. Можно прикрываться всякими там принципами, но на каждый принцип есть такой же замечательный противоположный принцип.

·> а не художественное произведение, раскрывающее внутренний мир автора.


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

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


Ох нелегко вам приходится — сидите там в цепях и гребёте. Серьёзно — вам бизнес даёт требования по сопровождаемости, тестируемости и всей прочей ерунде? Мне интересно. Вот прямо приходит бизнес и говорит: "если ты добавишь интерфейс, мы потратим лишние $100 долларов на оплату твоей работы, но скорее всего они не вернутся, поэтому не добавляй интерфейса" — это вот это называется "диктуется бизнес-требованиями"? Если скажут тесты не писать, даже глазом не моргнёте, лишь бы бизнес счастлив был?

R>>Один из вариантов представления этого в коде — использование компонентом X интерфейса к внешнему миру вместо самого внешнего мира. Это частный случай https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8/%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8 — для переиспользования X в нескольких разных "мирах" не нужно делать никаких правок в самом X, нужно просто добавлять новые реализации интерфейса и подсовывать их в X. Мне не надо ждать пока меня петух в задницу клюнет, чтобы увидеть разницу между связью "чтение CSV" — "запись в БД" (её нет) и, "чтение CSV" — "запись CSV" (механизмы для (де)экранирования строк наверняка будут одни и те же — и там, и там) Вы разницу видите?

·>Нет. У тебя был код чтения csv который дёргал handleUser — и ему было по барабану что там пишется в БД.

Да, у меня именно так и было.

·>И вообще разницы не было это метод интерфейса или класса. В реализации handleUser писалась БД и было по барабану кто дёргал этот метод. Добавление интерфейса в случае ровно одной реалицаии ничего не меняет.


не распарсил.

·>Не путай, "интерфейс" как абстрактное понятие модели кода и "интерфейс" как конструкция яп — разные понятия. Набор публичных методов класса это уже интерфейс.


Ды вроде не путаю.

R>>·>Писать простой код — вкусовщина?

R>>Да вы так с этим YAGNI носитесь, как будто это правда что-то. Ну кто-то предложил принцип, и дальше что? За ним нет исследований с цифрами, экспериментальных подтверждений, это просто "экспертное мнение". С этим мнением можно согласиться, можно не согласиться, можно иметь в виду, можно поспорить о границах применимости. OCP вон тоже принцип — "пишите код так, чтобы только дописывать и никогда не трогать уже написанное" — я не знаю если вы вообще его принимаете, но очевидно он у вас глубоко не на первом месте.
·>Рефакторинг "class UserHandler" -> "interface UserHandler" + "class DbUserHandler" не трогает уже написанное и с OCP не конфликтует.

Правки кода не трогают уже написанное. Окей

R>>Ну и прежде чем называть код простым, поделитесь вашими критериями простоты.

·>При прочих равных — чем короче, тем проще. Твой код длиннее, а в остальном я разницы не вижу.

"Я разницы не вижу" — я не готов искать истину в таком базисе

R>>Ну давайте совсем в лоб. Хорошая граница — это когда код читалки CSV идёт в отдельную библиотеку usercsvreader.dll и, блин, не тянет за собой драйвер Mysql В моём понимании адекватный код пишется именно с этим ограничением в голове.

·>А почему ты именно тут границу ставишь? Может лучше граница это когда код идёт в отдельный асинхронный скалируемый микросервис? Ну json там, калбеки, ретраи, таймауты, рекавери, балансинг... Библиотеки нынче уже не модно.

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

·>Или всё-таки лучше придерживаться необходимого минимума? "Всё должно быть изложено так просто, как только возможно, но не проще".


R>> В версии с интерфейсом оно будет именно так — взял и перетащил, никаких правок в коде.

·>А ты сделай diff между твоим
Автор: rosencrantz
Дата: 02.09.20
кодом и моим
Автор: ·
Дата: 02.09.20
. И заметь — реальных правок нет никаких, просто удалены лишние символы.


Какое интересное наблюдение
Re[16]: Интерфейсы и реализация
От: · Великобритания  
Дата: 05.09.20 12:52
Оценка:
Здравствуйте, rosencrantz, Вы писали:

R>·>Ну олимпиадники это не в тему, по-моему было очевидно, что я говорю в контексте промышленного программирования, когда цель — профессионально написанный код,

R>Это у вас такая цель? Что это вообще такое — "профессионально написанный код" расскажете? У меня такой цели нет. В моей реальности мы все принимаем технические решения и получаем за это зарплату. Что там профессиональный код, что непрофессиональный — это каждый сам себе перед зеркалом. Можно прикрываться всякими там принципами, но на каждый принцип есть такой же замечательный противоположный принцип.
Это понятно, я просто пытаюсь вернуть тебя в русло обсуждения. Твои возражения основанные об особенностях олимпиадного программирования — вообще не в тему. В олимпиадном программировании сабж вообще по барабану, там вряд ли вообще кто-либо даже классы использует, не говоря об интерфейсах.

R>·> а не художественное произведение, раскрывающее внутренний мир автора.

R>Ах, как завернул. Давай, плюй мне в душу. Мой внутренний мир он не хочет, видите ли Это называется навыки декомпозиции, а не внутренний мир. Есть один фундаментальный принцип — сложность надо резать на кусочки. Как именно резать — на это есть сотня противоречивых принципов сомнительного происхождения с неочевидной областью применимости, есть личный опыт, есть тараканы. Правильного ответа нет никогда. Есть только большое множество совсем неправильных, и меньшее множество удовлетворительных с плюсами и минусами.
С этим я не спорю. Резать надо, чтобы упростить поддержку кода, а значит удешевить разработку, что и есть одна из целей промышленного программирования. Суть моих возражений, что в твоём примере введения интерфейса разрез-то был, а вот сложности не было. В итоге сложность только увеличилась, а значит цель не достигнута.

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

R>Ох нелегко вам приходится — сидите там в цепях и гребёте. Серьёзно — вам бизнес даёт требования по сопровождаемости, тестируемости и всей прочей ерунде? Мне интересно. Вот прямо приходит бизнес и говорит: "если ты добавишь интерфейс, мы потратим лишние $100 долларов на оплату твоей работы, но скорее всего они не вернутся, поэтому не добавляй интерфейса" — это вот это называется "диктуется бизнес-требованиями"? Если скажут тесты не писать, даже глазом не моргнёте, лишь бы бизнес счастлив был?
В каком-то смысле да, ибо без бизнеса программисты не нужны, бизнес нас кормит. Конечно, бизнес так не говорит, он словьёв то таких не знает. Он измеряет деньгами. Если кто-то наворотил кучу лишнего кода с плохой сопровождаемостью и тестируемостью, то это выльется определённое количество денег на поддержку и внесение изменений. Вот и когда бизнес будет выбирать с кем работать — он выберет того, кто на языке бизнеса тратит меньше денег, т.е. в переводе на программистский язык — пишет простой и тестируемый код.

R>>>Один из вариантов представления этого в коде — использование компонентом X интерфейса к внешнему миру вместо самого внешнего мира. Это частный случай https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8/%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%BE%D1%81%D1%82%D0%B8 — для переиспользования X в нескольких разных "мирах" не нужно делать никаких правок в самом X, нужно просто добавлять новые реализации интерфейса и подсовывать их в X. Мне не надо ждать пока меня петух в задницу клюнет, чтобы увидеть разницу между связью "чтение CSV" — "запись в БД" (её нет) и, "чтение CSV" — "запись CSV" (механизмы для (де)экранирования строк наверняка будут одни и те же — и там, и там) Вы разницу видите?

R>·>Нет. У тебя был код чтения csv который дёргал handleUser — и ему было по барабану что там пишется в БД.
R>Да, у меня именно так и было.
Верно. И пофиг, что UserHandle будет class или interface.

R>·>И вообще разницы не было это метод интерфейса или класса. В реализации handleUser писалась БД и было по барабану кто дёргал этот метод. Добавление интерфейса в случае ровно одной реалицаии ничего не меняет.

R> не распарсил.
Тело метода handleUser пишет в бд. И кто вызывает метод — тоже пофиг. Т.е. твои "модули" можно выделить точно так же даже если не будет interface.

R>·>Не путай, "интерфейс" как абстрактное понятие модели кода и "интерфейс" как конструкция яп — разные понятия. Набор публичных методов класса это уже интерфейс.

R>Ды вроде не путаю.
csv и бд в том примере взаимодействуют через интерфейс, вне зависимости от того, есть ли "interface" как в твоём коде или напрямую используется "class" как в моём коде. Следовательно из двух решений надо выбрать то, которое короче.

R>>>Да вы так с этим YAGNI носитесь, как будто это правда что-то. Ну кто-то предложил принцип, и дальше что? За ним нет исследований с цифрами, экспериментальных подтверждений, это просто "экспертное мнение". С этим мнением можно согласиться, можно не согласиться, можно иметь в виду, можно поспорить о границах применимости. OCP вон тоже принцип — "пишите код так, чтобы только дописывать и никогда не трогать уже написанное" — я не знаю если вы вообще его принимаете, но очевидно он у вас глубоко не на первом месте.

R>·>Рефакторинг "class UserHandler" -> "interface UserHandler" + "class DbUserHandler" не трогает уже написанное и с OCP не конфликтует.
R>Правки кода не трогают уже написанное. Окей
OCP вообще-то об изменениях, меняющих поведение. Рефакторинг по определению — изменение не меняющее поведение.

R>>>Ну и прежде чем называть код простым, поделитесь вашими критериями простоты.

R>·>При прочих равных — чем короче, тем проще. Твой код длиннее, а в остальном я разницы не вижу.
R>"Я разницы не вижу" — я не готов искать истину в таком базисе
В смысле? Тебе лишь стоит показать, что разница есть.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.