Обновить
93
Юрий@m36

Пользователь

21
Подписчики
Отправить сообщение
В функциональных языках часто нет разницы между данными и кодом. Можно сказать, что данных нет — всё функции. Вполне общий подход.
Шарп не является функциональным языком. Но можно к этому подходить так: языки не связаны с парадигмами, они лишь в некоторой степени предопределяют стиль программирования на них.

Шарп вполне разрешает писать в функциональном стиле. Даже если бы в нем не было лямд и анонимных методов, он это бы позволял. Вопрос только в удобстве и читаемости кода.
Семантически, если представить опять этот пример и представить С++, как модель внутренней работы виртуальных методов, то стратегия и Dictionary — будет одно и то же. Вы можете написать класс Operation, унаследовать его нескольким классам и в каждом будет по переопределению метода операции. Внутри при компиляции получится такая же таблица с указателями на функции. Делаете стратегию — и вот у вас то же самое.
Казалось бы, зачем изобретать велосипед. Но создавая и заполняя Dictionary вы пишете меньше кода и не создаете не очень нужные почти без поведения классы. Второе — такой подход позволяет расширять в рантайме набор действий, не теряя всех прелестей типизации. Третье. Полиморфизм, построенный на передаче делегатов — мощнее ООП средств. Потому что он позволяет сделать всё, что может ООП (пример стратегии), так и много больше.

Такая интуитивная аналогия. Тяжело обосновать, но всё же. С помощью объектов вы можете моделировать некоторые вещи. А с помощью делегатов вы можете создавать язык. Т.е. с помощью ООП вы скрываете поведение за именами (инкапсулируете), а с помощью делегатов вы создаете такие ограничения и язык, с помощью которых вы можете делать потом любое поведение, не выходя за рамки. С помощью ООП (на виртуальных методах), по сути, вы кодите более одноразовый код.
Ну и свитч и структуры кода — еще более одноразовый код, чем ООП.

И повторюсь, я не защищаю крайность, я согласен с Вами, что свитч иногда значительно лучше, потому как он будет проще читаться и соответствовать текущим требованиям. А угадывать и делать заранее гибкий код — неблагодарное дело.

«С моей точки зрения, это не «общая», а _частная_ рекомендация, применяемая в ограниченном числе случаев.»
Извините, не могу сейчас нарыть ссылку. Кто-то из великих рекомендовал. Причем рекомендации были для языка С. Что сути не меняет.

«Угу. Работающее в конкретных случаях, которых, по моему опыту, меньшинство. „
Это опять вопрос крайностей. Мощное средство потому и мощное, что с помощью его можно решать как простые задачи, так и сложные. А вот немощное средство сложные задачи не решает. Вопрос только в языке программирования, к чему он предрасполагает и какой код будет более запутанный и сложный для восприятия, а какой — прямое выражение мысли.
Конечно.

Вот только есть разница между разными типами. Например. Если вы определяете переменную — возраст человека, то важнее суть, а не тип — целый или decimal или временной интервал.

Или если linq выражение возвращает некую коллекцию, то не важно, какую именно. Главное что коллекция и понятен тип элементов.

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

Еще раз этот пример:
var result = Function.SomeMethod();

Непонятно. Но, конечно, я не придираюсь, это не реальный пример. В реальных будут адекватные названия. Но тогда нужны правила именования. Допустим, у нас стандартный пример: типы Figure, Rectangle, Circle.
И вот мы именуем метод:
var result = Function.GetLastCircle();

тип result семантически нам нужен, потому что он определяет круг операций с ним. GetLast — добавили, допустим, для конкретного метода, чтобы объяснить смысл. А вот слово Circle просто обязано быть в имени, чтобы мы поняли, с чем имеем дело. Это хорошо и понятно. Но это выполняет также замена слова var на тип.

Circle result = Function.GetLastCircle();

Я не считаю такое действие лишним. Потому как внесение такого смысла в название метода является хорошим тоном, но никак не проверяется компилятором. Поэтому «доверяй но проверяй» — возможно программист из каких-то других соображений туда это слово поместил или имел ввиду тип из другого пространства имен. А вот явное указание типа переменной снимает последние сомнения.
Табличный метод — это только частный случай. Можно полиморфизм реализовывать виртуальными методами, а можно таблицами делегатов, что, например, внутри С++ и делается.

А по возможности реализовывать структурами данных, а не структурами кода — это общая рекомендация. Она не всегда уместна. Мы спорим о крайностях. Если нужен свич из 3-5 веток и больше не предвидится, то возможно это не нужно. А если и нужно будет, то можно будет переделать.
Но при равных условиях читаемости, вариант с данными предпочтительнее.

«А оно нужно кому-то?

Вот от этого вопроса и надо плясать. „

Конечно, только от этого и плясать. Я же описал варианты развития событий, когда оно может понадобиться.

И с нечитаемостью не всё очевидно. Заменять структуры кода на структуры данных и код представлять как данные — это мощное средство.
Вот этого всегда сторонился.
Например:
Dictionary<int,string> dic = new Dctionary<int,string>();
заменяется на:
var dic = new Dctionary<int,string>();
т.к. тут понятно, что мы ньюкаем.

А вот:
var result = Function.SomeMethod();
Не понятно. Хорошо компилятору, он умный. А я нет. Не хочу помнить наизусть, что SomMethod возвращает. И когда коллеги повально кругом этот var используют, мне сложнее в коде разобраться.

Может я не прав? Хочу узнать аргументацию против. Потому что я очень редко var использую. В случае, когда только действительно точный тип для восприятия не важен — результат линькью выражения, например.
Вполне нормально с читабельностью. На счет «поведение этого PerformOperation в один взгляд», то возможно, где-то сложнее. Но шарп, не тот язык, где код и данные — это одно и то же. И слышал где-то рекомендацию, что в императивных языках желательное, где это возможно, заменять структуры кода на структуры данных. Т.е. switch на Dictionary в данном случае. Чтобы не очень разносить заполнение словаря и метод, можно объявлять словарь и заполнять прямо в том же методе, где предполагался switch. При случае будет просто его вынести потом в поле экземпляра. Или еще обобщить — в статическое поле. Или еще в статическое свойство, которое кэширует изменения. И далее вообще сделать расширяющееся поведение в рантайме. Что нельзя было бы сделать с помощью switch

Это вопрос баланса, как где код расположить, чтобы видно было и понятно. Иногда switch и if предпочтительнее виртуальных методом. Эту же задачу можно решить «стратегией» на виртуальных методах. Суть та же, но кода будет больше и читаемость, думаю, хуже.
Предлагаю рассматривать язык программирования, как лингвистический язык изложения мыслей, а не язык конструирования алгоритмов. (И не только я предлагаю).
Если так его рассматривать, то становится понятно: если человек не знает самого языка программирования, то нечего ему и читать код. Нет смысла читать и понимать код по комментариям. Домохозяйкам и сантехникам это не нужно. Даже если они поймут, они не смогут править и чинить.
Поэтому я следую такому интуитивному правилу: код должен быть понятен, но без комментариев. Если при написании кода «просится» комментарий, значит следует посмотреть еще раз код, что-то в нем возможно не так. А уже потом, по остаточному принципу, писать комментарии (бывают и сложные алгоритмы или оптимизации, которые делают код не очевидным).
Конечно, эта логика не относится к описанию интерфейсов (или просто методов и классов).

Язык программирования — язык выражения мыслей. Если у человека не получается с ним так работать, он начинает выражать мысли на других языках — естественном или UML или не важно каком.

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

Если бы их не было, то как-то стремно код менять. Что-то падает только в платоновском мире идей. А когда оно здесь упадет — неизвестно.

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

Есть такая ерунда: когда я не писал тесты, то мне казалось, что я крут — я мог полдня писать, написать кучу кода, кучу классов, и запускал — оно сразу делало всё что надо, при первом запуске. А когда начал писать тесты, то стабильно нахожу еще до коммита один-два бага.

Потом, я переписал и перелопатил и изменил логику всего движок и еще одну важную систему в текущей конторе. Эта система работала уже. Любые сбои дорого стоят. И приятно, когда я два раза выкатывал практически на ходу — и всё бесшовно.

И на тесты не так много времени ушло. И на поддержку на самом деле не так много уходит.
«так как нет тестов»

Эта фраза всё убила. Нет тестов — следовательно нет рефакторинга. Кстати, и не будет нормального рефакторинга, если нет тестов.

А если нет рефакторинга, то вообще никак не будет происходит не только преждевременное, но и своевременное обобщение.
12 ...
31

Информация

В рейтинге
Не участвует
Откуда
Киев, Киевская обл., Украина
Дата рождения
Зарегистрирован
Активность