Командный игрок — старший разработчик с достаточными хардскиллами и сильными софтскиллами. Он умеет общаться, выстраивать конструктивные отношения с мидлами и другими сеньорами, с менеджментом, и при этом не рушит атмосферу в команде.
«Доктор Хаус» — специалист с запредельными техническими знаниями, который при этом может быть токсичным в общении, самоуверенным, нелюдимым, но способен закрыть критически важные задачи для бизнеса компании. Его возьмут, потому что без него проект встанет или вовсе пойдет под откос. Но брать таких людей — это исключение, а не правило.
В нынешних реалиях «Доктор Хаус» - это скорей специалист с адекватными для уровня сеньора знаниями.
Командный игрок - это очень часто балабол, который в старых реалиях еле дотягивал до мидла а сейчас получил возможность вместо скиллов успешно лить в уши работодателю.
Достаточно провести с десяток собеседований или хотя бы посмотреть их записи чтобы открыть для себя что современные командные сеньоры чаще всего не знают толком ни базовую базу ни даже язык программирования на котором они пишут но зато очень уверенно несут ахинею.
В программировании важны такие качества как: уситчивость, внимательность, дотошность, последовательный и вдумчивый подход и так уж вышло что такие качества ну очень часто есть у людей спокойных и замкнутых. Сливать таких людей в пользу болтунов, это конечно потрясающая логика.
Может быть так эффективнее работать? Ну например когда вместо того чтобы хороший специалист молча решил проблему за час, мы ее будем неделю обсуждать на созвонах, потому что все умеют обсуждать но никто не умеет решать. Главное же не решение проблем а создание видимости их решения. Или просто так комфортнее менеджеру которому меньше работы своей делать, меньше там разруливать, меньше находить подход к людям? Путь все вокруг станут приятными и беспроблемными болванчиками, так и напрягаться меньше. Интересно, что может пойти не так с таким подходом?
Представьте себе уголовный кодекс в котором написано что преступление карается правосудием, но при этом сам кодекс не содержал бы полного определения понятия преступление. Был бы от такого кодекса толк? Вроде и написано все правильно - нельзя совершать преступления, вот только что такое преступление не очень понятно и у каждого гражданина, правоохранителя, прокурора, адвоката и судьи свое понимание что это. Очевидно что всех внешней правильности, практического смысла от такого полезного кодекса нет.
Ровно тоже самое и с SOLID. Буквы - красивые, призывы - пафосные, толку - ноль. SRP - у класса должна быть одна ответственность. Какой смысл от принципа если нет методики определения этой самой ответственности? Если так то у каждого разработчика свои критерии что будет делать класс а следовательно, уберите SRP и ничего не поменяется - у каждого разработчика остануться свои критерии что будет делать класс. ISP - тоже самое. Без методики как понять сколько много а сколько мало - толку нет. Каждый будет делать столько сколько посчитает нужным. Зачем тогда ISP? OCP - напоминает очередное делай хорошо плохо не делай а что делать и как забыли подвести и все начинают трактовать как сами понимают.
Проблема SOLID что это просто мнение одного единственного человека 20 летней давности из которого сделали священную корову в придачу с религией, о котором уже 20 лет пишут статьи и шпаргалки и все никак не могут постигнуть. Причем мнение в стиле не делай плохо - делай хорошо, а как что такое хорошо я вам не скажу. Почему вроде бы инженерные принципы не могут постигнуть уже 20 лет? Да потому что они стали религиозными.
Пусть будет так. Для того чтобы это сделать нужно правило - как детерминировано определить какую единственную задачу должен решать класс. Где это правило?
Добавляй новую функциональность через новые классы/методы не меняя старые.
А если нужно поменять старые?
Дочерние классы должны соблюдать требования к родителю.
В оригинальном принципе нет ни слова про классы.
Дели большие интерфейсы на маленькие и специализированные.
Пусть будет так. А где правило согласно которого мы определяем что такое большие а что такое маленькие интерфейсы? Без этого правила принцип - это красивый и бесполезный набор слов.
Преждевременная оптимизация
→ Попытки «предусмотреть всё» ведут к переусложнению.
→ Пример: Создание интерфейса IReportExporter для единственной реализации PDFExporter. → Философия:«Не создавай абстракцию, пока нет реальной необходимости» (YAGNI+KISS > SOLID).
Причем здесь оптимизация? Оптимизация, в нашем контексте - это сокращение потребления ресурсов без потери функциональности, например процессора и памяти. Какое к этому имеют отношение создание каких то интерфейсов?
В сухом остатке так и не понятно из статьи. Есть абстрактный SOLID который непонятно как использовать а если использовать то еще и куча проблем может быть и нужно 10 раз подумать. А по итогу то нужно или нет? Если нужно то где обоснование что оно имеет больше плюсов чем минусов?
PS Статья написана нейронкой а ответы хотелось бы от автора получить.
Ну, подвинуть Java - это изначально не реалистичная цель была.
Вполне реалистичная. На том же андроиде Kotlin вообще вытеснил Java. Другой пример, как я уже писал - Go. Язык, у которого куча детских болячек, у которого не было ни экосистемы нормальной ни даже пакетного менеджера, плюс который откровенно недолюбливали многие за его примитивность. Т.е. по сравнению с Kotlin у которого на старте была уже вся экосистема и инструменты, там вообще все плохо. И тем не менее, он взлетел и откуси не то что у Java а у всего пула backend языков не слабый кусок рынка.
И вот получается, есть красивый милый приятный современный Kotlin с весьма скромными результатами на уровне приза зрительских симпатий. А есть кривой косой морально устаревший Go который при этом подвинул рынок. И еще раз повторю - все потому что Go было что предложить рынку кроме своей приятности а Kotlin - нет.
Это я не к тому что не люблю Kotlin а к тому - почему для этого языка дела сейчас обстоят так как обстоят.
Я не говорю что на Kotlin нет проектов или вакансий. Я о том что язык смысл которого был подвинуть Java со своей задачей не справился. Он зашел только на андроиде потому что там бесперспективняк. На бэкенде все очень скромно, особенно учитывая насколько дешево перейти на Kotlin - вся экосистема тажа самая, нужно заменить только язык и все. Но даже при таких благоприятных обстоятельствах и за столько лет Kotlin занимает очень скромную долю рынка. Ладно можно сказать много легаси, но новые проекты тоже продолжают массово стартовать на Java.
А почему так я уже написал - нет каких то серьезных позиций где Kotlin бы мог то что не может Java. Рантайм такой же, библиотеки такие же в большинстве. Корутины уже не преимущество. По производительности Kotlin даже чуть проигрывает Java. Остаеться чуть лучше синтаксис, закрытие какие то проблем да, чуть понадежнее да. Кому то норм, а кому то из разрабов будет влом забивать себе голову еще одним языком который чуть лучше. Многим компаниям, как выясняется, тоже влом заморачиваться с поиском котлинистов или переучиванием джавистов. Оно бы можно было, если была киллер фича, которая бы это оправдывала, но ее нет.
Хороший пример Go. У языка огромное количество проблем, но есть несколько киллерфич, за счет которых он взлетел, которые выделяют его на фоне других и которые являются аргументом для команды и компании, даже не смотря на то что там вообще отдельная молодая экосистема.
Поэтому можно конечно рассказывать что на нем пишут бэкенды - пишут, и что вакансии есть - есть, но по факту все это очень скромно для такого задела и стольких лет.
Но главная, я бы даже сказал капитальная проблема языка - это то что у него отсутствуют какие бы то ни было весомые киллер фичи отвечающие на вопрос разработчика или компании - зачем на него переходить. Улучшенный синтаксис и встроенные проверки - это вообще не аргумент.
Точнее, не так. У Kotlin была киллер-фича - быть мульти-языком для решения большинства проблем. Другими словами - это должен бы быть единый язык на котором бы писали и фронт и бэк и мобилку. Но идею не вывезли. KotlinJs особо никому не нужен. KMM оказался не лучшей идеей и не взлетел. Остался только KotlinJvm который по сути better java. Раньше хотя бы корутины были преимуществом, но с появление виртуальных потоков и они были нивелированы. Kotlin к сожалению сейчас ничего не может предоставить весомого чтобы било Java и было поводом перейти на этот язык.
Как показало время, как мне кажется, это и стало причиной того что язык взлетел только на андроиде.
Кто? В Java он есть, но я не видел чтобы его кто-то использовал.
Согласно Вашей же логике - нет, его там нет.
Или Вы имели в виду что в Java есть конструкции по смыслу представляющие из себя goto но называющиеся по другому? Ну окей.
Но если так, не очень понимаю претензию к моим комментариям где я пишут ровно тоже самое - в статье формально не упоминается ФП но по смыслу оно там есть?
В статье Гётц пишет, что ФП это когда всё это функция. Наверное он так и думает. И если бы он считал, что главное в истории с рекордами и паттерн матчингом это добавление в Джаву элементов ФП он бы так и сказал.
А еще он пишет что в ООП все есть объект. В Java половина языка - это не объекты, следовательно Java вообще не ООП язык? Или всетаки нет?
Там никто не стесняется, все все понимают и даже в названиях можно это увидеть: map, filter, compose, identity, никто не стал ничего придумывать заимствовали честно. Также ни для кого не секрет что паттерн матчинг это фича фп языков и в основе это оттуда пошло в другие языки. В ФП языка он по больше части нужен для работы с ADT. Удивительно но даже в тексте Гёца он прямо пишет про ADT, тоже одной из отличительных особенностей ФП. Но нет он не это имел ввиду разумеется, потому что не написал волшебное слово ФП.
Заходим для примера в оф документацию по Rust там не стесняясь:
We’ve already covered some other Rust features, such as pattern matching and enums, that are also influenced by the functional style.
И только в Java добавляют все тоже самое что и все другие но нет, это с ФП не связано.
Подхода "всё это функция" в Джаве нет и не планируется, понятия чистых функций нет и не планируется, за сайд эффектами никто не следит и не собирается.
Полноценного ООП в Rust/Go нет и не планируется что не мешает иметь методы.
Подхода "всё это функция" в Clojure нет и не планируется, понятия чистых функций нет и не планируется, за сайд эффектами никто не следит и не собирается. Но тем не менее это типичный ФП язык.
Что мешает Java развиваться перенимая фичи из ФП но не становясь чистым ФП языком? Загадка.
Циклы заменили стримами моментально, практически за ночь.
Джава сообщество, особенно того старого формата приняло такое за одну ночь? Не смешите мои тапочки, там у людей спустя годы истерика не проходила.
When we're modeling complex entities, OO techniques have a lot to offer us. But when we're modeling simple services that process plain, ad-hoc data, the techniques of data-oriented programming may offer us a straighter path.
Where OOP encourages us to use classes to model business entities and processes, smaller codebases with fewer internal boundaries will often get more mileage out of using classes to model data.
Что-то не так? Да есть ООП, да оно решает определенные задачи со всем уважением и мы с ним будем дружить и дальше но ветер перемен дует в другую сторону. Почему не написано так прямо и я интерпретировал фразу? Потому что Brian Goetz пишет весьма дипломатично и естественно не будет в открытую заявлять что нам приоритет сейчас не очень ООП. Почему я интерпретирую статью так хотя там в лоб так не написано? Очень просто, достаточно посчитать количество нововведений например начиная с Java 7 связанных с ООП и с ФП и все станет очевидно в каком направлении все движется.
Ну только Data Oriented Programming с функциональным программированием имеет примерно столько же общего, сколько с ООП. Рекорды имутабельные, имутабельность, конечно, ключевой компонент ФП, но не ключевой компонент Data Oriented Programming.
То о чём пишет Гётц это традиционный старый добрый процедурный подход. Данные отдельно, код, который их обрабатывает отдельно. Который да, де факто в серверных приложениях сейчас повсюду.
Да неужели. А если дальше почитать?
Algebraic data types
This combination of records and sealed types is an example of what are called algebraic data types (ADTs). Records are a form of "product types", so-called because their state space is the cartesian product of that of their components. Sealed classes are a form of "sum types", so-called because the set of possible values is the sum (union) of the value sets of the alternatives. This simple combination of mechanisms -- aggregation and choice -- is deceptively powerful, and shows up in many programming languages.
Но это разумеется совпадение.
неизменяемые структуры данных +
паттерн матрчинг +
алгебраические типы данных +
монадические типы вроде Optional +
Если это выглядит как ФП, пишеться как ФП и работает как ФП, то это, ... разумеется старый добрый процедурный подход.
А все потому что дальновидный Brian Goetz написал "Data Oriented Programming" видимо мудро предвосхищая что напиши он ФП то у фанатов ООП случиться истерика.
Меня поражает что во всех других языках ни у кого вообще нет проблем с тем что туда добавляют элементы ФП но только в Джаве происходит перевозбуждение от одной мысли что там может быть что-то не ООПшное.
Все намного проще. Pattern matching - это как и sealed classes, records и прочее - это история которая пришла в Java из функционального программирования.
А знаете почему? Потому что с годами оказалось что ООП не торт. Ну по крайне мере для серверного приложения, где главная задача обрабатывать данные а не состояния и там лучше подходит ФП. Java туда потихоньку двигается.
Главный архитектор Java Brian Goetz написал статью о том что ООП конечно мы уважаем и для каких то задач оно подходит но мы будем двигаться в сторону ФП.
Первое, руководство не имеет права выяснить на что человек подписан, это сбор данных о частно жизни, даже если руководство об это узнало случайно.
Если человек выкладывает это в открытый доступ то любой может этими данными пользоваться. Если же данные из закрытых источников то разумеется - нет.
Второе, это в любом случае не может быть основанием для увольнения.
Это и не является. Но является основанием для недоверия и поводом присмотреться к сотруднику с возможным дальнейшим разворотом событий.
Я не оправдываю кого-либо из них, но согласитесь, если работодатель узнает что работник подписан на паблик где рассказывают как обманывать работодателя, странно ожидать от работодателя лояльности.
Даже если человек состоит в таком сообществе, это ещё не значит, что он нарушает этику или халтурит. Судят всё же по делам, а не по подпискам.
Подобные шаги со стороны работодателя выглядят как попытка контролировать мышление сотрудников. Сегодня уволили за канал про «меркантильность», завтра — за лайк под каким-нибудь постом. Корпоративный контроль за убеждениями — это тревожный тренд, особенно в компании с гос-корнями.
Есть сотрудник работающий на ювелирной фабрике. Руководство выяснило что он подписан на паблик анонимных клептоманов.
Как же должно отреагировать руководство? Наверное проигнорировать, это же личное дело каждого что он там смотрит и читает? Или пойти срочно перепроверять его работу и как минимум взять на карандаш? Или это уже корпоративный контроль за убеждениями?
А теперь реальный способ чтобы у вас была команда а не рабочая группа:
прибыль должны делить все. Ну или хотя бы каждый должен понимать что и за что получает. Дураков креативить и вдохновлять общими миссиями не так много. В основном развод на миссии работает на джунов.На сеньоров, сказки про общее дело, дружную семью и прочие разводы с миссиями не очень работают
в команде не должно быть мудака-руководителя. Как бы вы все хорошо не построили, мудак-руководитель все равно все испортит
процессы должны создаваться из нужд команды а не команда подгоняться под процессы
не должно быть кумовства. Кумовство разрушит проект не так быстро как мудак-руководитель, но разрушит
руководитель должен быть в одной упряжке со своей командой
каждый член команды не должен чувствовать себя винтиком
все что делается командой, должно делаться зачем-то
Давайте, покажите, какие издержки у этой "виртуальной машины". Что там "тормозит". По какой причине код шарпа в принципе не может быть быстрее c++/rust.
В теории может в одном случае - когда у нас куча виртуальных методов и в CLR в рантайме сделал девиртуализацию и выполнение идет только по одной ветке все время. Но это все в теории.
Почему для C# проблемно быть на уровне Rust/C++?
Если представим что в C# нет сборщика мусора то причина в природе его работы. Rust/С++ значительно проще, для них прямой вызов это прямой вызов, им не нужны переходника для методов, у них нет ленивой загрузки, валидации, нет динамики. CLR из-за своей природы вынуждена делать кучу доп вычислений: JIT, поиски и загрузки, подмены переходников, валидацию, оптимизации и прочее прямо во время выполнения программы. Rust/C++ делают все что им нужно во время компиляции и практически не ограничены во времени и поэтому могут применять оптимизации любой сложности. В тоже время VM язык ограничен во времени оптимизации очень сильно.
VM языки умеют во время выполнения использовать особенности конкретного процессора и т.д. прекрасно. Делаете PGO для Rust/C++ и получаете тоже самое. Что дальше то? Что еще могут предоставить VM языки, считающие все и вся по ходу выполнения?
Разумеется есть у них тузы в рукаве, но эти тузы не про производительность.
Да называйте чем хотите. Я с первого сообщения пытаюсь донести мысль, что в дотнете код запускается точно также, как и нативный. Там нет никакой песочницы. Это нативно скомпилированный код, а не какая-то интерпретационная машина. И даже не виртуальная машина, потому что там нет виртуализации.
Вы либо не понимаете как это работает либо не можете донести о чем спорте. Нет CLR приложение не запускается также как нативный, иначе согласно здравой логике нам не нужна была бы среда выполнения CLR для его работы.
В какой формате находиться выполняемый код? В формате MSIL. Может ли операционная система запустить такое приложение? Нет не может и ничего про него не знает. Для того чтобы запустить приложение нам нужна программа которая будет эмулировать машину способную выполнять MSIL код, такие программы называются виртуальными машинами а точнее подвидом с названием process virtual machine. Можно даже на википедии найти такие базовые определения:
A process virtual machine, sometimes called an application virtual machine, or Managed Runtime Environment (MRE), runs as a normal application inside a host OS and supports a single process. It is created when that process is started and deleted when it is closed. Its purpose is to provide a platform-independent programming environment that abstracts away details of the underlying hardware or operating system and allows a program to execute in the same way on any platform.
Кто у нас запускает приложение? Само? Нет. Мы запускаем виртуальную машину и уже она загружает приложение и готовит его к запуску. Как виртуальная машина исполняет приложение: интерпретирует(Python), либо интерпретирует с элементами JIT компиляции(JS/Java), либо полностью JIT компилирует. Это не важно, это средства реализации со своими плюсами и минусами.
Приложение запускается,происходит загрузка и JIT необходимых метаданных, методов и точки входа Main().
Пруф
Before an object instance is created, the CLR looks up the loaded types, loads the type if not found, obtains the MethodTable address, creates the object instance, and populates the object instance with the TypeHandle value. The JIT compiler-generated code uses TypeHandle to locate the MethodTable for method dispatching. The CLR uses TypeHandle whenever it has to backtrack to the loaded type through MethodTable.
Запускается Main(). Действительно теперь код работает почти как нативный. Дальше в ходе выполнения нужно вызывать метод другого класса который еще не загружен. Что делать? Правильно, Main() передаст управление виртуальной машине которая пойдет искать новый класс в метаданных сборки, затем они будет его верифицировать и загружать в память (мне никто не мешает пойти в IL код и руками сделать там все что угодно после того как оно скомпилирован, поэтому VM вынуждена проверять все в первый раз).
Пруф
В процессе проверки код CIL проверяется в попытке убедиться, что код может получить доступ к расположениям памяти и вызывать методы только через правильные определенные типы.
Далее, как только метаданные загружены в память, нужно искать сам метод в таблице методов, в зависимости от типа это будет более или менее сложно. Но зачем нам искать метод?
Затем что в сыром виде у нас нет абсолютных адресов методов, а програжать всю сборку и связывать всех со всеми во время запуска никто в здравом уме не будет, все это выполняется лениво. Поэтому при первом вызове каждого метода мы вынуждены его искать затем проверять.
Пруф
Компиляция JIT учитывает возможность того, что некоторый код никогда не вызывается во время выполнения. Вместо использования времени и памяти для преобразования всего CIL в PE-файл в машинный код он преобразует CIL при необходимости во время выполнения и сохраняет полученный машинный код в памяти, чтобы он был доступен для последующих вызовов в контексте этого процесса. При загрузке и инициализации типа, загрузчик создает и присоединяет заглушку к каждому методу в этом типе. При первом вызове метода заглушка передает управление компилятору JIT, который преобразует CIL для этого метода в родной код и изменяет заглушку, чтобы она напрямую указывала на созданный родной код. Поэтому последующие вызовы JIT-скомпилированного метода переходят непосредственно в машинный код.
После того как мы нашли метод, нам нужно сделать JIT компиляцию. Это происходит во время выполнения только когда конкретный метод запускается первый раз. После того мы подменяем переходник в месте вызова и можем передать управление коду.
Скрытый текст
Перед запуском метода его необходимо скомпилировать в код, зависящий от процессора. Каждый метод, для которого был создан CIL, компилируется JIT при первом вызове, а затем выполняется. При следующем запуске метода выполняется существующий скомпилированный JIT-код машинного кода. Процесс JIT-компиляции и последующего выполнения кода повторяется до завершения выполнения.
Ах да, места вызовов. Допустим у нас есть класс A и метод fu() и он уже JITован. Далее мы вызываем метод bar() класса B. Если B не загружен мы вынуждены загрузить его. И вот проблема, у B весь код сырой в формате MSIL и ничего не знает про A. После загрузки B и JIT компиляции и вызова bar() он дойдет до fu(). Проблема в том что у bar() нет информации о том где лежит fu() и он вынужден ... искать этот метод в A и только потом менять переходник у себя. Выходит что мало просто один раз вызывать метод чтобы он JITанулся, нужно еще чтобы каждый целевой метод хотя бы раз его вызвал и поменял у себя переходники. Да, когда все они друг друга навызывают то код начнет работать почти как нативный. Почему почти? Потому что нативному коду это все не нужно, у него все посчитано при компиляции, ну максимум методы динамической библиотеки подключить да, у любого же языка с VM есть различные издержки в необходимости держать переходники и производить разрешения методов и метаданных. Такова их природа со своими плюсами и минусами.
Вот Вам мысли на подумать. И если требуете от меня что-то показывать и доказывать то извольте и сами.
Разумеется идеально, если не упоминать что на этом все плюсы микросервисов заканчиваются а все остальное превращается в сплошные минусы.
Микросервисы - это по сути жертва, на которую идут потому как по другому в сложившихся обстоятельствах никак, а не какое-то идеальное решение.
Ну между знает и не говорит и говорит но не знает я бы выбрал первое. Потому как первое еще можно исправить.
В нынешних реалиях «Доктор Хаус» - это скорей специалист с адекватными для уровня сеньора знаниями.
Командный игрок - это очень часто балабол, который в старых реалиях еле дотягивал до мидла а сейчас получил возможность вместо скиллов успешно лить в уши работодателю.
Достаточно провести с десяток собеседований или хотя бы посмотреть их записи чтобы открыть для себя что современные командные сеньоры чаще всего не знают толком ни базовую базу ни даже язык программирования на котором они пишут но зато очень уверенно несут ахинею.
В программировании важны такие качества как: уситчивость, внимательность, дотошность, последовательный и вдумчивый подход и так уж вышло что такие качества ну очень часто есть у людей спокойных и замкнутых. Сливать таких людей в пользу болтунов, это конечно потрясающая логика.
Может быть так эффективнее работать? Ну например когда вместо того чтобы хороший специалист молча решил проблему за час, мы ее будем неделю обсуждать на созвонах, потому что все умеют обсуждать но никто не умеет решать. Главное же не решение проблем а создание видимости их решения. Или просто так комфортнее менеджеру которому меньше работы своей делать, меньше там разруливать, меньше находить подход к людям? Путь все вокруг станут приятными и беспроблемными болванчиками, так и напрягаться меньше. Интересно, что может пойти не так с таким подходом?
На этом можно и закончить.
Представьте себе уголовный кодекс в котором написано что преступление карается правосудием, но при этом сам кодекс не содержал бы полного определения понятия преступление. Был бы от такого кодекса толк? Вроде и написано все правильно - нельзя совершать преступления, вот только что такое преступление не очень понятно и у каждого гражданина, правоохранителя, прокурора, адвоката и судьи свое понимание что это. Очевидно что всех внешней правильности, практического смысла от такого полезного кодекса нет.
Ровно тоже самое и с SOLID. Буквы - красивые, призывы - пафосные, толку - ноль.
SRP - у класса должна быть одна ответственность. Какой смысл от принципа если нет методики определения этой самой ответственности? Если так то у каждого разработчика свои критерии что будет делать класс а следовательно, уберите SRP и ничего не поменяется - у каждого разработчика остануться свои критерии что будет делать класс.
ISP - тоже самое. Без методики как понять сколько много а сколько мало - толку нет. Каждый будет делать столько сколько посчитает нужным. Зачем тогда ISP?
OCP - напоминает очередное делай хорошо плохо не делай а что делать и как забыли подвести и все начинают трактовать как сами понимают.
Проблема SOLID что это просто мнение одного единственного человека 20 летней давности из которого сделали священную корову в придачу с религией, о котором уже 20 лет пишут статьи и шпаргалки и все никак не могут постигнуть. Причем мнение в стиле не делай плохо - делай хорошо, а как что такое хорошо я вам не скажу. Почему вроде бы инженерные принципы не могут постигнуть уже 20 лет? Да потому что они стали религиозными.
Пусть будет так. Для того чтобы это сделать нужно правило - как детерминировано определить какую единственную задачу должен решать класс. Где это правило?
А если нужно поменять старые?
В оригинальном принципе нет ни слова про классы.
Пусть будет так. А где правило согласно которого мы определяем что такое большие а что такое маленькие интерфейсы? Без этого правила принцип - это красивый и бесполезный набор слов.
Причем здесь оптимизация? Оптимизация, в нашем контексте - это сокращение потребления ресурсов без потери функциональности, например процессора и памяти. Какое к этому имеют отношение создание каких то интерфейсов?
В сухом остатке так и не понятно из статьи. Есть абстрактный SOLID который непонятно как использовать а если использовать то еще и куча проблем может быть и нужно 10 раз подумать. А по итогу то нужно или нет? Если нужно то где обоснование что оно имеет больше плюсов чем минусов?
PS Статья написана нейронкой а ответы хотелось бы от автора получить.
Вполне реалистичная. На том же андроиде Kotlin вообще вытеснил Java. Другой пример, как я уже писал - Go. Язык, у которого куча детских болячек, у которого не было ни экосистемы нормальной ни даже пакетного менеджера, плюс который откровенно недолюбливали многие за его примитивность. Т.е. по сравнению с Kotlin у которого на старте была уже вся экосистема и инструменты, там вообще все плохо. И тем не менее, он взлетел и откуси не то что у Java а у всего пула backend языков не слабый кусок рынка.
И вот получается, есть красивый милый приятный современный Kotlin с весьма скромными результатами на уровне приза зрительских симпатий. А есть кривой косой морально устаревший Go который при этом подвинул рынок. И еще раз повторю - все потому что Go было что предложить рынку кроме своей приятности а Kotlin - нет.
Это я не к тому что не люблю Kotlin а к тому - почему для этого языка дела сейчас обстоят так как обстоят.
@devmark @ermadmi78
Я не говорю что на Kotlin нет проектов или вакансий. Я о том что язык смысл которого был подвинуть Java со своей задачей не справился. Он зашел только на андроиде потому что там бесперспективняк. На бэкенде все очень скромно, особенно учитывая насколько дешево перейти на Kotlin - вся экосистема тажа самая, нужно заменить только язык и все. Но даже при таких благоприятных обстоятельствах и за столько лет Kotlin занимает очень скромную долю рынка. Ладно можно сказать много легаси, но новые проекты тоже продолжают массово стартовать на Java.
А почему так я уже написал - нет каких то серьезных позиций где Kotlin бы мог то что не может Java. Рантайм такой же, библиотеки такие же в большинстве. Корутины уже не преимущество. По производительности Kotlin даже чуть проигрывает Java. Остаеться чуть лучше синтаксис, закрытие какие то проблем да, чуть понадежнее да. Кому то норм, а кому то из разрабов будет влом забивать себе голову еще одним языком который чуть лучше. Многим компаниям, как выясняется, тоже влом заморачиваться с поиском котлинистов или переучиванием джавистов. Оно бы можно было, если была киллер фича, которая бы это оправдывала, но ее нет.
Хороший пример Go. У языка огромное количество проблем, но есть несколько киллерфич, за счет которых он взлетел, которые выделяют его на фоне других и которые являются аргументом для команды и компании, даже не смотря на то что там вообще отдельная молодая экосистема.
Поэтому можно конечно рассказывать что на нем пишут бэкенды - пишут, и что вакансии есть - есть, но по факту все это очень скромно для такого задела и стольких лет.
У Kotlin есть и плюсы и минусы перед Java.
Но главная, я бы даже сказал капитальная проблема языка - это то что у него отсутствуют какие бы то ни было весомые киллер фичи отвечающие на вопрос разработчика или компании - зачем на него переходить. Улучшенный синтаксис и встроенные проверки - это вообще не аргумент.
Точнее, не так. У Kotlin была киллер-фича - быть мульти-языком для решения большинства проблем. Другими словами - это должен бы быть единый язык на котором бы писали и фронт и бэк и мобилку. Но идею не вывезли. KotlinJs особо никому не нужен. KMM оказался не лучшей идеей и не взлетел. Остался только KotlinJvm который по сути better java. Раньше хотя бы корутины были преимуществом, но с появление виртуальных потоков и они были нивелированы. Kotlin к сожалению сейчас ничего не может предоставить весомого чтобы било Java и было поводом перейти на этот язык.
Как показало время, как мне кажется, это и стало причиной того что язык взлетел только на андроиде.
Ваш же комментарий выше по поводу goto в Java:
Согласно Вашей же логике - нет, его там нет.
Или Вы имели в виду что в Java есть конструкции по смыслу представляющие из себя goto но называющиеся по другому? Ну окей.
Но если так, не очень понимаю претензию к моим комментариям где я пишут ровно тоже самое - в статье формально не упоминается ФП но по смыслу оно там есть?
Определитесь уже.
А еще он пишет что в ООП все есть объект. В Java половина языка - это не объекты, следовательно Java вообще не ООП язык? Или всетаки нет?
Там никто не стесняется, все все понимают и даже в названиях можно это увидеть: map, filter, compose, identity, никто не стал ничего придумывать заимствовали честно. Также ни для кого не секрет что паттерн матчинг это фича фп языков и в основе это оттуда пошло в другие языки. В ФП языка он по больше части нужен для работы с ADT. Удивительно но даже в тексте Гёца он прямо пишет про ADT, тоже одной из отличительных особенностей ФП. Но нет он не это имел ввиду разумеется, потому что не написал волшебное слово ФП.
Заходим для примера в оф документацию по Rust там не стесняясь:
И только в Java добавляют все тоже самое что и все другие но нет, это с ФП не связано.
Полноценного ООП в Rust/Go нет и не планируется что не мешает иметь методы.
Подхода "всё это функция" в Clojure нет и не планируется, понятия чистых функций нет и не планируется, за сайд эффектами никто не следит и не собирается. Но тем не менее это типичный ФП язык.
Что мешает Java развиваться перенимая фичи из ФП но не становясь чистым ФП языком? Загадка.
Джава сообщество, особенно того старого формата приняло такое за одну ночь?
Не смешите мои тапочки, там у людей спустя годы истерика не проходила.
Что-то не так? Да есть ООП, да оно решает определенные задачи со всем уважением и мы с ним будем дружить и дальше но ветер перемен дует в другую сторону. Почему не написано так прямо и я интерпретировал фразу? Потому что Brian Goetz пишет весьма дипломатично и естественно не будет в открытую заявлять что нам приоритет сейчас не очень ООП. Почему я интерпретирую статью так хотя там в лоб так не написано? Очень просто, достаточно посчитать количество нововведений например начиная с Java 7 связанных с ООП и с ФП и все станет очевидно в каком направлении все движется.
Да неужели. А если дальше почитать?
Но это разумеется совпадение.
неизменяемые структуры данных +
паттерн матрчинг +
алгебраические типы данных +
монадические типы вроде Optional +
Если это выглядит как ФП, пишеться как ФП и работает как ФП, то это, ... разумеется старый добрый процедурный подход.
А все потому что дальновидный Brian Goetz написал "Data Oriented Programming" видимо мудро предвосхищая что напиши он ФП то у фанатов ООП случиться истерика.
Меня поражает что во всех других языках ни у кого вообще нет проблем с тем что туда добавляют элементы ФП но только в Джаве происходит перевозбуждение от одной мысли что там может быть что-то не ООПшное.
Нужно читать комментарий на который отвечаете
Поздравляю! Вы воюете не туда.
Все намного проще. Pattern matching - это как и sealed classes, records и прочее - это история которая пришла в Java из функционального программирования.
А знаете почему? Потому что с годами оказалось что ООП не торт. Ну по крайне мере для серверного приложения, где главная задача обрабатывать данные а не состояния и там лучше подходит ФП. Java туда потихоньку двигается.
Главный архитектор Java Brian Goetz написал статью о том что ООП конечно мы уважаем и для каких то задач оно подходит но мы будем двигаться в сторону ФП.
Data Oriented Programming in Java
Не нужно заглядывать глубоко в прошлое, когда ответ перед носом.
С каждой такой статьей невольно приходит мысли что современный HR это не про найм а про вредительство и саботаж.
Если человек выкладывает это в открытый доступ то любой может этими данными пользоваться. Если же данные из закрытых источников то разумеется - нет.
Это и не является. Но является основанием для недоверия и поводом присмотреться к сотруднику с возможным дальнейшим разворотом событий.
Я не оправдываю кого-либо из них, но согласитесь, если работодатель узнает что работник подписан на паблик где рассказывают как обманывать работодателя, странно ожидать от работодателя лояльности.
Есть сотрудник работающий на ювелирной фабрике. Руководство выяснило что он подписан на паблик анонимных клептоманов.
Как же должно отреагировать руководство? Наверное проигнорировать, это же личное дело каждого что он там смотрит и читает? Или пойти срочно перепроверять его работу и как минимум взять на карандаш? Или это уже корпоративный контроль за убеждениями?
А теперь реальный способ чтобы у вас была команда а не рабочая группа:
прибыль должны делить все. Ну или хотя бы каждый должен понимать что и за что получает. Дураков креативить и вдохновлять общими миссиями не так много. В основном развод на миссии работает на джунов.На сеньоров, сказки про общее дело, дружную семью и прочие разводы с миссиями не очень работают
в команде не должно быть мудака-руководителя. Как бы вы все хорошо не построили, мудак-руководитель все равно все испортит
процессы должны создаваться из нужд команды а не команда подгоняться под процессы
не должно быть кумовства. Кумовство разрушит проект не так быстро как мудак-руководитель, но разрушит
руководитель должен быть в одной упряжке со своей командой
каждый член команды не должен чувствовать себя винтиком
все что делается командой, должно делаться зачем-то
В теории может в одном случае - когда у нас куча виртуальных методов и в CLR в рантайме сделал девиртуализацию и выполнение идет только по одной ветке все время. Но это все в теории.
Почему для C# проблемно быть на уровне Rust/C++?
Если представим что в C# нет сборщика мусора то причина в природе его работы. Rust/С++ значительно проще, для них прямой вызов это прямой вызов, им не нужны переходника для методов, у них нет ленивой загрузки, валидации, нет динамики. CLR из-за своей природы вынуждена делать кучу доп вычислений: JIT, поиски и загрузки, подмены переходников, валидацию, оптимизации и прочее прямо во время выполнения программы. Rust/C++ делают все что им нужно во время компиляции и практически не ограничены во времени и поэтому могут применять оптимизации любой сложности. В тоже время VM язык ограничен во времени оптимизации очень сильно.
VM языки умеют во время выполнения использовать особенности конкретного процессора и т.д. прекрасно. Делаете PGO для Rust/C++ и получаете тоже самое. Что дальше то? Что еще могут предоставить VM языки, считающие все и вся по ходу выполнения?
Разумеется есть у них тузы в рукаве, но эти тузы не про производительность.
Вы либо не понимаете как это работает либо не можете донести о чем спорте. Нет CLR приложение не запускается также как нативный, иначе согласно здравой логике нам не нужна была бы среда выполнения CLR для его работы.
В какой формате находиться выполняемый код? В формате MSIL. Может ли операционная система запустить такое приложение? Нет не может и ничего про него не знает. Для того чтобы запустить приложение нам нужна программа которая будет эмулировать машину способную выполнять MSIL код, такие программы называются виртуальными машинами а точнее подвидом с названием process virtual machine. Можно даже на википедии найти такие базовые определения:
Кто у нас запускает приложение? Само? Нет. Мы запускаем виртуальную машину и уже она загружает приложение и готовит его к запуску. Как виртуальная машина исполняет приложение: интерпретирует(Python), либо интерпретирует с элементами JIT компиляции(JS/Java), либо полностью JIT компилирует. Это не важно, это средства реализации со своими плюсами и минусами.
Приложение запускается,происходит загрузка и JIT необходимых метаданных, методов и точки входа Main().
Пруф
Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects
Запускается Main(). Действительно теперь код работает почти как нативный. Дальше в ходе выполнения нужно вызывать метод другого класса который еще не загружен. Что делать? Правильно, Main() передаст управление виртуальной машине которая пойдет искать новый класс в метаданных сборки, затем они будет его верифицировать и загружать в память (мне никто не мешает пойти в IL код и руками сделать там все что угодно после того как оно скомпилирован, поэтому VM вынуждена проверять все в первый раз).
Пруф
Процесс управляемого выполнения
Далее, как только метаданные загружены в память, нужно искать сам метод в таблице методов, в зависимости от типа это будет более или менее сложно. Но зачем нам искать метод?
Затем что в сыром виде у нас нет абсолютных адресов методов, а програжать всю сборку и связывать всех со всеми во время запуска никто в здравом уме не будет, все это выполняется лениво. Поэтому при первом вызове каждого метода мы вынуждены его искать затем проверять.
Пруф
Процесс управляемого выполнения
После того как мы нашли метод, нам нужно сделать JIT компиляцию. Это происходит во время выполнения только когда конкретный метод запускается первый раз. После того мы подменяем переходник в месте вызова и можем передать управление коду.
Скрытый текст
Процесс управляемого выполнения
Ах да, места вызовов. Допустим у нас есть класс A и метод fu() и он уже JITован. Далее мы вызываем метод bar() класса B. Если B не загружен мы вынуждены загрузить его. И вот проблема, у B весь код сырой в формате MSIL и ничего не знает про A. После загрузки B и JIT компиляции и вызова bar() он дойдет до fu(). Проблема в том что у bar() нет информации о том где лежит fu() и он вынужден ... искать этот метод в A и только потом менять переходник у себя. Выходит что мало просто один раз вызывать метод чтобы он JITанулся, нужно еще чтобы каждый целевой метод хотя бы раз его вызвал и поменял у себя переходники. Да, когда все они друг друга навызывают то код начнет работать почти как нативный. Почему почти? Потому что нативному коду это все не нужно, у него все посчитано при компиляции, ну максимум методы динамической библиотеки подключить да, у любого же языка с VM есть различные издержки в необходимости держать переходники и производить разрешения методов и метаданных. Такова их природа со своими плюсами и минусами.
Вот Вам мысли на подумать. И если требуете от меня что-то показывать и доказывать то извольте и сами.