Смена основного стека с .NET на Java



    Хочу описать свои наблюдения и впечатления о самом популярном языке серверного программирования для Enterprise под названием Java. Наблюдения и впечатления на сравнении и контрасте с “похожей” платформой .NET, с которой я очень хорошо знаком. Уверен, что ~год назад, когда будущее нового дотнета в очередной раз показалось мне чересчур туманным и мысль сменить технологический стек окончательно материализовалась в голове, данная статья оказалась бы очень полезной. Я постараюсь не вдаваться в мелкие технические/стилистические различия языков программирования, которые легко нагуглить, а предложу скорее взгляд сверху — на экосистему в целом. Итак, Java глазами матёрого дотнетчика с десятилетним стажем. Прошу под кат.

    Disclaimer


    Когда-то давно у меня уже возникали похожие мысли написать про интересные отличия Microsoft Sql Server / Oracle, в стиле “ух ты, нету типа bool”, “длинные транзакции это норма, серьезно?”, “как это нет авто-коммита в настройках по умолчанию” и т.д. Но внутренний перфекционист всё думал, что я еще “недостаточно долго и хорошо всё изучил”, “где-нибудь ошибусь”, “поспешишь людей насмешишь” и т.д. — всё откладывал на “попозже”, а потом все впечатления буквально смылись и писать стало нечего. Так что в этот раз я решил слишком долго не ждать, иначе писать снова может стать не о чем. Поэтому отдельная просьба указывать мне на неточности, если они присутствуют. А я в свою очередь постараюсь не вдаваться в банальности “как же неудобно писать без var” (уже дождались на днях Java 10), “extension methods отсутствуют” и прочие “type erasure” и "multiline-strings".
    Итак, экосистема.

    1. IDE и терминология


    В .NET выбор очевиден — Visual Studio. Работа в студии идет с проектами (projects), которые сгруппированы в солюшн (последний то .sln, то .json, то снова .sln, не сильно важно). Всё достаточно просто.

    В мире Java в качестве IDE внимания на данный момент заслуживают двое парней — это Intellij Idea и Eclipse. На “постсоветском пространстве” первая победила. У зарубежных авторов эклипс живее всех живых. Казалось бы, какая разница чем пользуешься, хоть блокнотом, но в этом месте сразу же возникает проблема в терминологии.

    В Eclipse самый верхний уровень — workspace, который состоит из projects.
    В Idea самый верхний уровень — project, который состоит из modules.

    В какой терминологии общаться разработчикам, использующим разные IDE, неясно. Часто принято общаться в терминологии “сборщиков”. Так, в случае например maven, дистрибутив собирается из модулей (modules), которые сгруппированы в pom-нике.

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

    Отдельно хочу отметить бины (Beans). В .Net никому не придет в голову вводить новые термины для обычных классов, зарегистрированных в контейнере. На многих проектах контейнеры вообще не используются, даже в 2018 году (да, на это больно смотреть, но я это наблюдал и ни раз). В мире Java наоборот — культ контейнера и часто принято общаться в терминах бинов.

    2. Сборка проекта


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

    В мире .Net как средство управления пакетами/зависимостями используется nuget, для сборки — msbuild.

    В Java всё склеено в один инструмент (впрочем, здесь снова есть выбор — Maven или Gradle). К каждому существует куча плагинов. В кровавом интерпрайзе доминирует первый.

    Есть очень удобные wrapper-ы над сборщиками, позволяющие просто взять и начать сборку (кто сталкивался с поиском нужных версий msbuild-а на разных машинах, меня поймёт).

    Дотнет сейчас тоже пытается двигаться в эту же сторону (привет, Cake).

    3. Прикладные фреймворки


    Здесь абсолютное доминирование Java-платформы. Есть два основных монстра: EJB и Spring с огромнейшей экосистемой и практиками “вокруг”. Доминирует второй. Со временем он тоже стал большим и сложным, поэтому даже придумали фреймворк для фреймворка — Spring Boot. Который, хочу отдать должное, действительно сильно облегчает жизнь.

    В .Net ничего этого нет. Зато есть изобретение велосипедов “в каждом проекте по-своему”. Вплоть до выбора нужного DI/IoC-контейнера на вкус разработчика (если разработчик вообще в курсе про существование контейнеров) и решение как управлять транзакциями (если разработчик опять же знает, что такое транзакции и кто-то догадался отключить автокоммит на Sql Server-е). Разве что ASP.NET MVC немного похож на Spring MVC (который лишь малая часть Spring Framework).

    4. Сервер приложений


    И был IIS един и монолитен. И поняли Микрософт, что System.Web это плохо. И придумали OWIN. Впрочем, адекватные альтернативы IIS под Windows от этого не появились (да я знаю про Kestrel для .Net Core).

    В Java выбор огромный, есть Servlet API, или новенький Reactive Streams(привет .Net Async Controllers) и множество реализаций, из которых Tomcat одна из самых популярных “коробочных”.

    5. Community


    Java Community Process и этим всё сказано. Формальный процесс, в котором заинтересованные лица могут участвовать в обсуждении и формировании новых версий платформы.

    Только спустя 15 лет в Микрософт поняли, что это хорошо и пора перестать диктовать миру “как правильно жить” (помните ныне расформированный Microsoft Patterns and Practices group?) и придумал аналог — .NET Foundation.

    6. Работа с БД


    Это до сих пор не до конца понятный для меня момент, почему люди продолжают использовать JPQL в 2018 году. Единственное объяснение, которое я нашел, состоит в том, что типизированная Criteria — ужасна и многословна.

    Это одно из немногих мест, где дотнетчикам повезло больше, т.к. 99% запросов к БД в .NET пишутся на типизированном Compile-time LINQ.

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

    7. XML hell


    До сих пор популярно заблуждение, что java — это тонны xml когда. Но на текущем этапе развития экосистемы это совсем не так. Скорее даже наоборот! Я могу написать web-приложение на Java без единой строчки xml (привет Spring Boot), и не могу это сделать на .Net (привет web.config, который “по сути” тот же web.xml, только еще и перемешанный с конфигом).

    Выводы


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

    P.S.: На КПДВ — старое, но еще смешное видео.
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну, и что?
    Реклама
    Комментарии 196
    • +5
      и не могу это сделать на .Net (привет web.config, который “по сути” тот же web.xml, только еще и перемешанный с конфигом).

      Я вот пишу облачные микросервисы в Azure (serverless и webapp) и чот мне ни разу не потребовалось включать web.config в проект. Всё можно из кода настроить. Пишу под netcoreapp2.0
      Максимум для удобства быстрой настройки логирования или параметров приложения вообще (connection strings) подключается app.config (который JSON)

      • –2

        Спасибо за комментарий. Сфокусированность микрософта на своем личном облаке это одна из вещей, которая меня очень настораживает в. net core и почему я не очень верю в его будущее (по крайней мере в российских реалиях). Весь кровавый интерпрайз попытались оставить в старом заброшенном .net 4.6+ и всё переписать заново в core где сегодня csproj (xml), завтра json (который project) а потом опять xml (решили все-таки не выкидывать msbuild), зато в entity framework core банально уже n лет нет lazy loading (т. е. оно не Enterprise ready). Для облаков и микросервисов в них .net core возможно действительно вполне себе ок.

        • +1
          В версии 2.1 уже есть.
          • 0
            нет lazy loading (т. е. оно не Enterprise ready)
            ибо
            This release is still in preview.
            • 0
              Выше уже ответили что еще не зарелизилось.
              А как насчет many-to-many отношений?
              • 0
                А как насчет many-to-many отношений?

                Так ли велика эта проблема?
                • 0
                  Заставляет плодить новые сущности там где они не нужны.
                  • 0
                    Почему же не нужны? Связная сущность отражает структуру базы данных. К костылям или какому-то неочевидному ужасу в коде не приводит. А уж что лучше: явность или неявность — это дискуссионный вопрос.
            • +1
              Естественно, они этим зарабатывают. Но .Net Core и Azure никак не связаны. Core реально кроссплатформенно (не зря они сделали Linux Subsystem в Win10). А еще поддержка Docker из коробки. Да с EF Core есть проблемы, но учитывая, что он написан с нуля, он взрослеет с каждым релизом. Ну и с выпуском .Net Core платформа переродилась. О ней говорят и пишут больше.
              • 0
                Core реально кроссплатформенно (не зря они сделали Linux Subsystem в Win10).

                Как связаны .NET Core и WSL?
                • 0
                  Возможность тестировать и писать .net core приложения сразу в Linux. Сразу после анонса WSL появилось много статей как настроить .net core и VS Code в WSL
                  • 0
                    Возможность тестировать и писать .net core приложения сразу в Linux.
                    Вы же про нативный докер и прочие специфичные инструменты, которые нормально работают только в Linux-окружении? Иначе разрабатывать кроссплатформенное приложение, используя WSL в качестве референса целевой платформы — это выглядит немного странно, как по мне.
                    • 0
                      Целевая платформа всё-таки это Linux. Я считаю возможность разработки в WSL одной из причин появления последней.
              • 0
                Да и выбор типа проекта был на стадии RC, с релиза 1.0 тип проекта не менялся.
                • –1
                  LazyLoading скорее вреден чем бесполезен и очень хорошо там, где его нет.
                • 0

                  Более того, в ASP.NET Core web.config вообще отсутствует (он генерится только при публикации)


                  Существуют следующие поставщики конфигурации:


                  • Форматы файлов (INI, JSON и XML).
                  • аргументы командной строки.
                  • Переменные среды.
                  • Объекты .NET в памяти.
                  • Незашифрованное хранилище Secret Manager (Диспетчер секретов).
                  • Зашифрованное пользовательское хранилище, например Azure Key Vault.
                  • Пользовательские поставщики (установленные или созданные).
                • +3
                  Сразу скажу, что отношусь к java и java-сообществу, как собратам .net.
                  И был IIS един и монолитен… да я знаю про Kestrel для .Net Core

                  Над Kestrel можно и Nginx или IIS в качестве прокси.

                  Я могу написать web-приложение на Java без единой строчки xml и не могу это сделать на .Net

                  netcore?
                  Вот весь xml, который был автосгенерён. Больше трогать его не надо.
                  <?xml version="1.0" encoding="utf-8"?>
                  <configuration>
                    <system.webServer>
                      <handlers>
                        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
                      </handlers>
                      <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
                    </system.webServer>
                  </configuration>


                  Есть два основных монстра: EJB и Spring с огромнейшей экосистемой и практиками “вокруг”. В .Net ничего этого нет. Вплоть до выбора нужного DI/IoC-контейнера на вкус разработчика

                  Очень сомнительный минус, и очень сомнительный плюс.
                  • 0
                    Вся ирония в том, что некоторое время назад все.нетчики подкалывали джавистов про «программирование на xml». А сейчас этот самый xml остался, как необходимость, как раз в .Net.
                    • +3
                      Я программирую в .net и не имею необходимости использовать xml.
                      Что я делаю не так?
                    • 0
                      Впрочем, адекватные альтернативы IIS под Windows от этого не появились (да я знаю про Kestrel для .Net Core)

                      Зато появилась альтернатива Java под Linux.
                      Размещение в Linux с использованием Nginx
                      Размещение в Linux с использованием Apache

                    • 0
                      Кстати, в Visual Studio файлы проектов уже можно писать с нуля руками, как это делается с Maven/Gradle, или там всё ещё чёртов ад, править который без гуя рука не поднимется?
                      • +1
                        Кстати, в Visual Studio файлы проектов уже можно писать с нуля руками

                        Уж пару лет как. Не уверен за самую раннюю версию msbuild, которая может понимать сокращённый *.csproj, но чтобы написать webapp какой-нибудь достаточно пару строчек.

                        • 0
                          И новые PackageReference руками добавляете?
                          • +1
                            И новые PackageReference руками добавляете?

                            Ну я вас умоляю, мы ж не в каменном веке. Package Manager'ы же есть.

                            • 0
                              Причем здесь каменный век, в Java тоже есть пакетные менеджеры и появились они гораздо раньше чем возник тот же nuget. Но вот принято референсы прям в pom.xml руками прописывать. Вопрос привычки и удобства. Поначалу выглядит странновато, но по факту на самом деле оказывается удобней чем отдельный CLI.
                              • 0

                                В .Net есть варианты (перечислю самые, на мой взгляд, популярные):


                                • Отличный GUI в Rider/Visual Studio (и частично через Command Palette в VS Code)
                                • dotnet CLI (dotnet add package Newtonsoft.Json)
                                • Ручками в csproj (нет подсказок по именам/версиям)
                                • Nuget Package Manager (CLI / package.config, который ужасен)
                                • Paket (CLI / paket.dependencies, который прекрасен + есть lock файл с транзитивными зависимостями)
                              • 0
                                Еще есть расширение для VS Code vscode-nuget-package-manager с автоподсказками
                            • +2
                              Еще ни разу «матерый дотнетчик с десятилетним стажем» не был так близок к провалу.
                              • 0
                                Вы слишком токсичны. Но я плюсанул, радуйтесь.
                              • 0
                                Не поверите, но через CLI, ведь nuget-manager включен в cli tools у dotnetcore:
                                dotnet add package Newtonsoft.Json

                                Так же есть выбор добавить через GUI от разных IDE: VSC, Rider, VS.
                          • 0
                            Есть два основных монстра: EJB и Spring с огромнейшей экосистемой и практиками “вокруг”.


                            EJB — это не фреймворк. Может быть автор хотел сказать Java EE (Jakarta EE). EJB — это всего лишь одна из спек Java EE

                            • +1
                              JEE мне кажется некорректно использовать в данном контексте, т.к. это набор спек, половину из которых входят тот же спринг.

                              EJB это грубо говоря контейнер (я верю что вы это знаете, просто пишу для синхронизации терминологического контекста) и именно альтернативой ему стал в свое время спринг. Это собирательное название для «того что не спринг» и именно эту аббревиатуру обычно не пишут в спринговых вакансиях.

                              Но концептуально вы правы, наиболее корректно использовать JEE Server (именно эту бирку «лепят» (или лепили?) себе всякие jboss-ы). Или уже правильно Jakarta Server? :)
                              • +1
                                JEE Server означает, что у данного продукта есть сертификация реализации Java EE. Например, тот же Wildfly имеет сертификацию по Java EE 7, но не имеет по Java EE 8.
                                С Jakarta пока не понятно, в каком виде будет сертификация и будет ли вообще.
                                • 0
                                  Эталонная реализация Java EE 8 — GlassFish 5.0.
                            • +1
                              Всем, кто переходит с VisualStudio, советую только IDEA. Когда переходил (очень давно), думал что умнее студии ничего нет, но IDEA приятно удивила и продолжает удивлять до сих пор. И ReSharper от тех же JetBrains, которые делает студию умнее и удобнее, тому подтверждение.
                              • +4
                                В .NET выбор очевиден — Visual Studio.
                                Как же Rider?
                                • +2
                                  Отсутствует бесплатная версия, аналогичная VS Community
                                  • 0
                                    Это имеет мало значения, если большинство компаний и так покупает платную студию, да еще и решарпер. Idea с поддержкой всякого EE тоже стоит денег, если сравнивать. Тем более, что это единственное адекватное решение для .NET-разработки из *nix.
                                    Для Rider есть достаточно милая инди-лицензия, позволяющая разрабатывать на ней хоть лично для себя, хоть чужой лютый интерпрайз (проблемы совместимости я обнаружил только для некоторых T4-шаблонов, но это специфика).
                                    • 0

                                      Это только до тех пор, пока не покупается решарпер.

                                    • 0
                                      Скорее всего схвачу минусов (на хабре культ Jetbrains), но это хайп. Да еще и платный.
                                      Я года 3-4 работал с VS Community и ни одной мысли о Pro не возникало — хватало всего что есть. А в Idea Community со спрингом нормально работать невозможно — сделано всё чтобы люди платили деньги.
                                      • –1
                                        Я года 3-4 работал с VS Community и ни одной мысли о Pro не возникало — хватало всего что есть.
                                        Вы/организация точно не нарушали Community-лицензию при этом? Ведь при желании можно и райдер «покрякать» и считать бесплатным.
                                        А решарпер (который всего на $10 дешевле райдера) вы тоже принципиально не используете?

                                        сделано всё чтобы люди платили деньги.
                                        Вы так говорите, будто это что-то плохое. Коммерческая фирма делает качественные инструменты и просит за это деньги! То ли дело MS, которая выпускает эсклюзивную Visual Studio для своей платной операционной системы!
                                        • –1
                                          Не нарушал я ничего, речь идет о домашнем компьютере и pet-проектах. Visual Studio Community хватает «на всё что угодно» (в отличие от ужасающей Express которая была ранее давно). А вот в IDEA Community жадинки отрезали использование спринга с бутом, что отвратительно и неприятно.
                                          • 0
                                            Не нарушал я ничего, речь идет о домашнем компьютере и pet-проектах.
                                            Там может каждый делать то, что ему вздумается. Я все же про прямое назнчение инструментов — интерпрайз. MS молодцы, конечно, но у них такие меры — не от лучшей жизни.
                                            Вопрос про решарпер все так же актуален.

                                            А вот в IDEA Community жадинки отрезали использование спринга с бутом
                                            Вам maven там тоже отрезали?)
                                            • 0
                                              Что же это за контейнер такой, которым без специальной поддержки от IDE пользоваться отвратительно и неприятно?
                                              • +1
                                                Почему-то все забыли про NetBeans IDE. А в ней достаточно инструментария для создания Java9 и Java EE 7- приложений, которые можно тут же в среде тестировать в GlassFish 5.x и WildFly 12, собирать метрики и протоколы обмена (http-monitor), а maven является родным форматом организации проектов на Java. Интегрированы Git и Mercurial-плагины (используют внешние git и hg) для прозрачного сохранения изменений в коде — можно буквально щелчком мыши откатиться на определённый коммит в истории изменений.
                                                • 0
                                                  Что именно там отрезали от сприг бута?
                                                  Почему тогда у меня проекты на спринг буте прекрасно работают в IDEA Community?
                                                • 0
                                                  Почитал лицензию. А что трактуется под «одновременным использованием»?
                                                  • +2
                                                    То ли дело MS, которая выпускает эсклюзивную Visual Studio для своей платной операционной системы!

                                                    Это утверждение ложно. В VS можно делать приложения для Android, Linux, iOS, Windows. Что касается "платной операционной системы", то JetBrains Rider для индивидуалов без решарпера стоит 139$ в год пруфлинк + Linux = 7 942 рубля, Windows 10 Home стоит 5 500 руб пруфлинк + Visual Studio Community = 5 500 руб


                                                    Напомню, что разница между VS про и коммюнити только в отсутствии CodeLens в последней и лицензией для инди либо опенсоурс разработок.


                                                    Итого по гамбурскому счету разница в пользу МС — 2 500 руб.


                                                    Цифры не лгут.

                                                    • 0
                                                      Это утверждение ложно
                                                      Внезапно. Под Linux тоже версия данной IDE есть?

                                                      JetBrains Rider для индивидуалов без решарпера стоит 139$ в год пруфлинк + Linux = 7 942 рубля, Windows 10 Home стоит 5 500 руб пруфлинк + Visual Studio Community = 5 500 руб
                                                      … и еще решарпер сверху за $129 (=
                                                      • 0

                                                        Линукс не нужен. Шучу. МС с удовольствием сделали бы версию под Линукс, но пока не могут — слишком долго портировать такого монстра. С другой стороны, судя по темпам развития, энтузиазму контрибюторов и по опросу StackOverflow VS Code, уже обогнал всех и вышел на первое место, так что для Линукcа он может стать основным продуктом из семейства Visual Studio. Аминь.

                                                        • 0
                                                          МС с удовольствием сделали бы версию под Линукс, но пока не могут — слишком долго портировать такого монстра.

                                                          Очевидно, что если бы MS не сделало бесплатной студию, то с таким подходом рынок они бы потеряли уже в обозримом будущем.

                                                          он может стать основным продуктом из семейства Visual Studio

                                                          Но он не станет Visual Studio (= Начало конца уже положено в его технологических основах.
                                                          • 0
                                                            VS Code к VS имеет такое же отношение, как слово «котлета» к «коту». Не позволяйте бренду смысл затмевать, а то так еще можно случайно сказануть, что есть студия на мак.
                                                        • 0
                                                          Цифры действительно не лгут. А вот люди их применяющие их, вполне могут…
                                                  • 0
                                                    Да, я знаю про jOOQ, но ни разу не видел его использование хоть в чем-то, напоминающем продакшен. Возможно потому что это полу-платный новодел без JSR, возможно по другой причине.


                                                    В защиту jOOQ'а скажу, что во всю используем в продакшене энтерпрайза: гораздо очевиднее, чем JPQL/Criteria Builder, а в сочетании с правильной готовкой миграций даёт управляемую работу с БД. Почему-то JPQL/Criteria Builder считают, что разработчики не могут в SQL, поэтому предлагают навернуть абстракций там, где можно обойтись понятным и проверяем (во время компиляции) кодом.
                                                    • 0
                                                      Есть вариант с iBatis/MyBatis для любителей SQL. И Spring Data для сильно нелюбящих. Довольно много в последнем запросов можно просто сделать названием методов.
                                                      • 0
                                                        И Spring Data для сильно нелюбящих. Довольно много в последнем запросов можно просто сделать названием методов.

                                                        Можно, но в какой-то момент начинаешь очень сильно предпочитать явное неявному.
                                                    • +1
                                                      На многих проектах контейнеры вообще не используются, даже в 2018 году (да, на это больно смотреть, но я это наблюдал и ни раз).


                                                      Контейнеры головного мозга
                                                      • 0
                                                        По моему опыту отсутствие контейнеров в .net — это говнокод в 90% случаев. Статистика. :)
                                                        • 0
                                                          Говнокод — это не отсутствие контейнеров, а неосиливание DI.
                                                          Карго-культ контейнера от этого не спасает.
                                                      • 0

                                                        Я бы рекомендовал поближе присмотреться к .Net Core, лично мне кажется C# куда как продуктивнее Java. Да и тенденции в мире также смотрят в сторону .Net ...

                                                        • +4
                                                          Да и тенденции в мире также смотрят в сторону .Net ...

                                                          Это какие например?
                                                          • +2
                                                            C# куда как продуктивнее Java.

                                                            А что под этим подразумевается, можно поподробнее?

                                                            • 0
                                                              Нормальные генерики (существующие и в рантайме), непримитивные типы-значения, много меньший объем синтаксического словоблудия, LINQ.
                                                              • 0
                                                                Ни одно из слов к продуктивности не имеет отношения.
                                                                • +2

                                                                  … к продуктивности программиста? Я не соглашусь, дженерики сильно на это влияют, expression trees — тоже.

                                                                  • 0
                                                                    Можете мне привести пример частого использования expression trees в кровавом энтерпрайзе? Мне действительно интересно.
                                                                    Последний раз я их ковырял когда правил форк от ORM и больше «с ходу» не припомню необходимости.

                                                                    Про дженерики тоже холиварный вопрос, в джаве они есть, причем с неплохой ковариантностью-контрвариантностью из коробки, ala
                                                                    List<? extends A> myList1
                                                                    List<? super B> myList2
                                                                    Ну да, type erasure. Сейчас минусаторы набегут, но в большинстве повседневных задачах он не мешает.

                                                                    Мы же про продуктивность? Почему не вспоминаем про тот же Lombok
                                                                    @NonNull
                                                                    @AllArgsConstructor
                                                                    @ToString
                                                                    @EqualsAndHashCode
                                                                    Getter/@Setter

                                                                    Вот это про продуктивность. И никакого бойлерплейта.
                                                                    В дотнете такое возможно огромными костылями ala Postsharp (который почти загнулся из-за платности / заметно возрастающего времени компиляции), ну или Fody (который тоже не оч.популярен). Появилось ли что-то похожее в .Core?
                                                                    • 0
                                                                      Не, это не про продуктивность. Про продуктивность в Java — Kotlin :) И его я тоже больше 2х лет использую в продакшне в энтерпрайзе. Там все эти костыли не нужны.
                                                                      • +1
                                                                        Можете мне привести пример частого использования expression trees в кровавом энтерпрайзе?
                                                                        Составление фильтров.
                                                                        • +3
                                                                          Можете мне привести пример частого использования expression trees в кровавом энтерпрайзе?

                                                                          LINQ, AutoMapper, FluentAssertions. Мы вот у себя только что маленький внутренний движок критериев на expression tree сделали.


                                                                          Почему не вспоминаем про тот же Lombok

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

                                                                          • –1
                                                                            Разве что LINQ принимается :)
                                                                            Да и-то в качестве «запросов к БД» или куда-либо ещё.
                                                                            Что автомаппер что FluentAssertions, что Linq2Objects на простых лямдах достаточно нормально отжимаются.
                                                                            • 0
                                                                              Разве что LINQ принимается

                                                                              Вы просили пример использования — вы их получили. То, что это можно сделать иначе — понятное дело; но это не значит, что иначе сделать удобнее.


                                                                              Что автомаппер что FluentAssertions, что Linq2Objects на простых лямдах достаточно нормально отжимаются.

                                                                              И как вы из простой лямбды получите описание провалившегося assertion?

                                                                          • +1
                                                                            Почему не вспоминаем про тот же Lombok
                                                                            Getter/@Setter

                                                                            … так в C# это не нужно уже черт знает сколько, auto properties же.


                                                                            @NonNull

                                                                            С nullability планируют расправляться намного более системно.

                                                                            • 0
                                                                              Ну не черт сколько, возможность на авто-пропертях делать readonly setter появилась достаточно недавненько.

                                                                              Плюс если вспомнить любимого Рихтера, то он ненавидит проперти со времен первого издания своей книги про CLR и говорит что стоит явно писать методы, которые не несут «многозначности то-ли переменная то ли метод» :D
                                                                              Но это я уже подтроливаю немножко, да. Еще Рихтер везде sealed рекомендовал, помнится.
                                                                              • 0
                                                                                Ну не черт сколько, возможность на авто-пропертях делать readonly setter появилась достаточно недавненько.

                                                                                Ну так никто все сразу и не обещал.


                                                                                Плюс если вспомнить любимого Рихтера, то он ненавидит проперти со времен первого издания своей книги про CLR

                                                                                Это вопрос вкуса.

                                                                            • 0
                                                                              Появилось ли что-то похожее в .Core?

                                                                              /// Example of a simple immutable record 
                                                                              type FinalGameScore = 
                                                                                  /// Game property
                                                                                  Game: string
                                                                                  /// FinalScore property
                                                                                  FinalScore: int
                                                                              
                                                                              


                                                                              Появилось… 13 лет назад… F# называется… Здесь вам и ToString и NotNull и Equals и HashCode и Serializable уже реализовано. Только, судя по популярности F#, это нафик не нужно никому… Энтерпрайз же, там люди серьёзные. Решарпером генерим.

                                                                              Касаемо мейнстрима — общают Records завести в С#. Status: InProgress.
                                                                              А пока вот аналогичный код на C#
                                                                              /// <summary>
                                                                              ///  Example of a simple immutable record 
                                                                              /// </summary>
                                                                              [Serializable]
                                                                              public sealed class FinalGameScore :
                                                                                  IEquatable<FinalGameScore>,
                                                                                  IStructuralEquatable,
                                                                                  IComparable<FinalGameScore>,
                                                                                  IComparable,
                                                                                  IStructuralComparable
                                                                              {
                                                                                  internal string _Game;
                                                                                  internal int _FinalScore;
                                                                                  
                                                                                  /// <summary>
                                                                                  /// Game property
                                                                                  /// </summary>
                                                                                  public string Game get => _Game;
                                                                              
                                                                                  /// <summary>
                                                                                  /// FinalScore property
                                                                                  /// </summary>
                                                                                  public int FinalScore get  =>_FinalScore;
                                                                                   
                                                                                  /// <summary>
                                                                                  /// Constructor 
                                                                                  /// </summary>
                                                                                  public FinalGameScore(string game, int finalScore)
                                                                                  {
                                                                                      this._Game = game;
                                                                                      this._FinalScore = finalScore;
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Needed for custom equality
                                                                                  /// </summary>
                                                                                  public int GetHashCode(IEqualityComparer comp)
                                                                                  {
                                                                                      if (this != null)
                                                                                      {
                                                                                          int num = 0;
                                                                                          int offset = -1640531527;
                                                                                          num = offset + (this._FinalScore + ((num << 6) + (num >> 2)));
                                                                                          string _game = this._Game;
                                                                                          return offset + (((_game == null) ? 0 : _game.GetHashCode()) + ((num << 6) + (num >> 2)));
                                                                                      }
                                                                                      return 0;
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Needed for custom equality
                                                                                  /// </summary>
                                                                                  public sealed override int GetHashCode()
                                                                                  {
                                                                                      return this.GetHashCode(LanguagePrimitives.GenericEqualityComparer);
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom equality
                                                                                  /// </summary>
                                                                                  public bool Equals(object obj, IEqualityComparer comp)
                                                                                  {
                                                                                      if (this == null)
                                                                                      {
                                                                                          return obj == null;
                                                                                      }
                                                                                      FinalGameScore finalGameScore = obj as FinalGameScore;
                                                                                      if (finalGameScore != null)
                                                                                      {
                                                                                          FinalGameScore finalGameScore2 = finalGameScore;
                                                                                          return string.Equals(this._Game, finalGameScore2._Game)
                                                                                              && this._FinalScore == finalGameScore2._FinalScore;
                                                                                      }
                                                                                      return false;
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom equality
                                                                                  /// </summary>
                                                                                  public bool Equals(FinalGameScore obj)
                                                                                  {
                                                                                      if (this != null)
                                                                                      {
                                                                                          return obj != null
                                                                                              && string.Equals(this._Game, obj._Game)
                                                                                              && this._FinalScore == obj._FinalScore;
                                                                                      }
                                                                                      return obj == null;
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom equality
                                                                                  /// </summary>
                                                                                  public sealed override bool Equals(object obj)
                                                                                  {
                                                                                      FinalGameScore finalGameScore = obj as FinalGameScore;
                                                                                      return finalGameScore != null && this.Equals(finalGameScore);
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom comparison
                                                                                  /// </summary>
                                                                                  public int CompareTo(FinalGameScore obj)
                                                                                  {
                                                                                      if (this != null)
                                                                                      {
                                                                                          if (obj == null)
                                                                                          {
                                                                                              return 1;
                                                                                          }
                                                                              
                                                                                          int num = string.CompareOrdinal(this._Game, obj._Game);
                                                                                          if (num < 0)
                                                                                          {
                                                                                              return num;
                                                                                          }
                                                                                          if (num > 0)
                                                                                          {
                                                                                              return num;
                                                                                          }
                                                                              
                                                                                          int _finalScore = this._FinalScore;
                                                                                          int _finalScore2 = obj._FinalScore;
                                                                                          if (_finalScore < _finalScore2)
                                                                                          {
                                                                                              return -1;
                                                                                          }
                                                                              
                                                                                          return (_finalScore > _finalScore2) ? 1 : 0;
                                                                                      }
                                                                                      else
                                                                                      {
                                                                                          if (obj != null)
                                                                                          {
                                                                                              return -1;
                                                                                          }
                                                                                          return 0;
                                                                                      }
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom comparison
                                                                                  /// </summary>
                                                                                  public int CompareTo(object obj)
                                                                                  {
                                                                                      return this.CompareTo((FinalGameScore)obj);
                                                                                  }
                                                                              
                                                                                  /// <summary>
                                                                                  ///  Implement custom comparison
                                                                                  /// </summary>
                                                                                  public int CompareTo(object obj, IComparer comp)
                                                                                  {
                                                                                      FinalGameScore finalGameScore = (FinalGameScore)obj;
                                                                                      FinalGameScore finalGameScore2 = finalGameScore;
                                                                                      if (this != null)
                                                                                      {
                                                                                          if ((FinalGameScore)obj == null)
                                                                                          {
                                                                                              return 1;
                                                                                          }
                                                                                          int num = string.CompareOrdinal(this._Game, finalGameScore2._Game);
                                                                                          if (num < 0)
                                                                                          {
                                                                                              return num;
                                                                                          }
                                                                                          if (num > 0)
                                                                                          {
                                                                                              return num;
                                                                                          }
                                                                                          int _finalScore = this._FinalScore;
                                                                                          int _finalScore2 = finalGameScore2._FinalScore;
                                                                                          if (_finalScore < _finalScore2)
                                                                                          {
                                                                                              return -1;
                                                                                          }
                                                                                          return (_finalScore > _finalScore2) ? 1 : 0;
                                                                                      }
                                                                                      else
                                                                                      {
                                                                                          if ((FinalGameScore)obj != null)
                                                                                          {
                                                                                              return -1;
                                                                                          }
                                                                                          return 0;
                                                                                      }
                                                                                  }
                                                                              
                                                                              }
                                                                              

                                                                              • 0
                                                                                Хоспадя, причем здесь F#
                                                                                • +1
                                                                                  Появилось ли что-то похожее в .Core?

                                                                                  Вы задали вопрос про .NET Core, а не про С#, так ведь?

                                                                                  • 0

                                                                                    Что характерно, вопросов, причем тут котлин, не возникало.

                                                                                    • +1
                                                                                      Хоспадя, причем здесь F#

                                                                                      Я сам из тех, которые на F# лепят.
                                                                                      Он очень даже при том.


                                                                                      Получаете кучу бонусов в языке, синтаксисе, системе типов, но теряете немного в IDE (Visual Studio днищенски поддерживает F#, VS Code — норм, Rider EAP 2018.1 уже тоже норм), в тулах (нет ничего подобного R#, но учитывая что язык гораздо менее бойлерплейтный и защищает от ошибок намного сильнее, надобность уже не та. Так же нет нормальных декомпиляторов, если dotPeek'ом тыкаться, получаем бесплатную обфускацию)


                                                                                      А главное dll те же, dotnet xxx.dll всё так же работает, поэтому хоть в Azure, хоть в AWS Lambda заливается абсолютно одинаково.
                                                                                      Ну и если чо, компилятор и темплейты проектов F# в .NetCore SDK уже встроены.


                                                                                      Поэтому встречный вопрос:
                                                                                      А почему не F#?

                                                                                  • 0
                                                                                    Можете почитать мою статью про кодогенерацию. Там не то, что AllAgrsConstructor можно определить, но и вообще все что угодно, включая создание и использование новых токенов.
                                                                                    • +1
                                                                                      Почему не вспоминаем про тот же Lombok

                                                                                      Потому что инструменты с вплетением байт-кода есть и для дотнета: от Fody до PostSharp.
                                                                                      Для NotNull в дотнете хватает системы типов (благодаря тем самым, не имеющим отношения к вашей личной продуктивности, генерикам и структурам): я, например, просто могу писать NotNull<T> и это будет та же самая ссылка на класс без оверхеда, но с гарантией, что null там нет.


                                                                                      с неплохой ковариантностью-контрвариантностью из коробки

                                                                                      Согласно Джону Скиту, это единственное преимущество языка Java над C#.


                                                                                      в большинстве повседневных задачах он не мешает

                                                                                      Ну да, конечно. Если я в параметре конструктора укажу IEnumerable<TypeName>, то дотнетные контейнеры автоматически подставят мне все зарегистрированные реализации для TypeName.
                                                                                      В яве это не сработает по построению. Именно поэтому явовские контейнеры на фоне дотнетных смотрятся убого.
                                                                                      Если потребуется оптимизация по аллокации памяти в куче, в яве придется делать специальные алгоритмы с использованием только примитивных типов.


                                                                                      Getter/@Setter

                                                                                      В дотнете для этого костыли не нужны — все уже есть прямо в языке.

                                                                                      • 0
                                                                                        Вообще-то сработает, как минимум в Spring с этим проблем нет и это используется.
                                                                                        А работает это потому, что несмотря на type erasure, информация о типах вполне себе доступна в runtime, через reflection.
                                                                            • –1
                                                                              .Net Core это попытка выкинуть платформу, разрабатываемую 15 последних лет и переписать/переосмыслить всё заново. Насколько эта идея может быть успешна в нынешних реалиях, покажет только время.
                                                                              Но то что большинство текущих проектов на .NET (не Core) внезапно стало Legacy — это факт.
                                                                              • 0

                                                                                .NET (не Core) достаточно легко переходит в .Net Core, в обратную тоже может, но уже труднее — хотя с каждой новой версией это все проще...

                                                                            • +2
                                                                              Ох, какая холиварная пятничная статья :)
                                                                              В .Net ничего этого нет. Зато есть изобретение велосипедов “в каждом проекте по-своему”. Вплоть до выбора нужного DI/IoC-контейнера на вкус разработчика (если разработчик вообще в курсе про существование контейнеров) и решение как управлять транзакциями (если разработчик опять же знает, что такое транзакции и кто-то догадался отключить автокоммит на Sql Server-е). Разве что ASP.NET MVC немного похож на Spring MVC (который лишь малая часть Spring Framework).

                                                                              .Net Core принес встроенный DI, который покрывает 95% нужд. И что вообще плохого в выборе DI/IoC-контейнера самостоятельно из существующих? Лучше иметь одну прибитую гвоздями реализацию?

                                                                              Про транзакции немного не понял, их управление строится через конфигурацию ORM, как и в мире Java. Или речь о распределенных?

                                                                              Опять-таки .Net Core предлагает многое, из того, что есть в Spring Framework (если, конечно, описание его состава на википедии не врет). Не все, но многое. Остальные вещи можно найти, установить и «подружить».

                                                                              И был IIS един и монолитен. И поняли Микрософт, что System.Web это плохо. И придумали OWIN.

                                                                              OWIN дал возможность более гибко и прозрачно конфигурировать пайплайн http-запроса через middleware.

                                                                              В общем, на вкус и цвет — фломастеры разные.
                                                                              • –1
                                                                                Наконец-то принес, спустя 15 лет. Минусов «выбора» масса — в одном проекте Unity, в другом — Autofac, в третьем StructureMap, а в четвертом NInject — и все они различаются в API и при этом одинаковые на 95%. Здесь огромный плюс джавовских JSR виден, надеюсь, всем.

                                                                                Транзакции — скорее про аннотацию @Transactional.

                                                                                OWIN еще и Embended Server дает. Еще немного, и Микрософт придумают свой H2 (или уже придумали?).
                                                                                • 0
                                                                                  в одном проекте Unity, в другом — Autofac, в третьем StructureMap, а в четвертом NInject — и все они различаются в API и при этом одинаковые на 95%. Здесь огромный плюс джавовских JSR виден, надеюсь, всем.

                                                                                  В том же ASP.NET MVC адаптируются в IDependencyResolver.
                                                                                  • 0
                                                                                    В том же ASP.NET MVC адаптируются в IDependencyResolver.

                                                                                    Опускаясь на уровень этого интерфейса все эти контейнеры полностью теряют уникальные фичи (Ninject — auto discovery, SimpleNinject — проверку на собираемость и т.д.) что делает наличие такого большого кол-ва реализации контейнеров бессмысленным.

                                                                                    • +2
                                                                                      А джавовые стандарты этой проблемы лишены?
                                                                                      • +1

                                                                                        Не теряют. Этот интерфейс — он для потребителя, вам ничто не мешает использовать уникальные фичи в composition root. Более того, скажем, у Autofac есть всякие милые штуки типа Func<T> и Lazy<T>, которые и на стороне потребителя видны.

                                                                                    • 0
                                                                                      Контейнер — это всего лишь инструмент для декларативного описания точки сборки, его замена в нормальном проекте — чисто техническая, причем несложная задача.
                                                                                      Если для в вашем проекте контейнер лезет куда-то еще, значит ваша команда не осилила DI.
                                                                                      Аннотации — магия из каменного века и антипаттерн.
                                                                                      Явовские контейнеры после дотнетных ужасны.
                                                                                      • 0
                                                                                        Composition Root оно называется и подобным образом на русский язык не переводится.
                                                                                        Точка сборки — это к Кастанеде Карлосу ;)

                                                                                        Явовские контейнеры можно конфигурировать кучей способов (сходу назову штук 5), при этом бут добавляет удобную авто-конфигурацию «из коробки». Не будьте столь категоричны, это неконструктивно и неприятно читать.
                                                                                  • 0
                                                                                    Для сборок еще кое где встречается старый добрый ant.
                                                                                    • 0
                                                                                      К счастью не застал :)
                                                                                    • 0
                                                                                      Вставлю и я свои 5 копеек. Всю жизнь был .NET developer, иногда хотелось поработать с Java, узнать как там и у них и перейдя в новую фирму стал больше Java Developer чем .NET. Что сразу бросилось в глаза:
                                                                                      1) IntelliJ лучше чем Visual Studio. Хотя VS+ReSharper стирает все преимущества IntelliJ, но всё же ReSharper добавляет свои проблемы (не знаю исправили баг или нет, но RS очень не любит WPF и в нашем проекте, плагин для VS, у нас почти все xaml.cs файлы были красные из-за того, что он не видел зависимости или что-то в этом роде), IntelliJ свои баги, тоже есть, но всё же для меня IntelliJ было приятным открытием
                                                                                      2) Очень неудобная настройка билдов (maven). Кроме того, что это огромные файлы xml, так в той же intellij нет(либо я не нашёл) GUI для управлением этим файлом и чтения зависимостей. Gradle почти тоже самое, правда все же файлы не такие огромные
                                                                                      3) Как же плохо без дефолтных фреймворков. Что я имею ввиду — огромное количество разных orm, библиотек логирования и т.д. Кому-то это плюс но в корпо это ужас ибо работаешь с разными программистами, с разных стран, у всех свои стандарты и пожелания. В итоге в проекте у нас 3 библиотеки для логов, ибо каждый вбил что хотел в свое время, используется MyBatis который конечно быстрый, но неудобный и вообще Spring Boot сейчас уничтожает все апгрейды у нас в проекте, потому что у нас Spring 3, сделали апдейт до 4, а дальше уже тяжело, ибо нужны новые версии зависимых других библиотек, а они все почти уже имеют настройки под Spring Boot. Ясно, что можно и под обычный настроить Spring, но если нет документации, то на это уходит много времени. Как пример — сейчас нам надо сделать Gateway и мы такие обрадовались, ведь в Spring Cloud появился как раз Gateway. Только фигушки нам ибо зависимости идут на Spring Boot и нет ещё статей на тему как поставить это на обычный Spring. К тому же очень мало статей на тему hello world в spring security на обычный spring. Найти конечно можно, но всё равно большинство под Spring Boot. В итоге сейчас думаем, что надо переноситься на Spring Boot 2, но у нас там столько зависимостей и не факт что все они имеют апдейт до SB2 и Spring 5. Вообщем ад и в .net даже близко такого не было никогда. В .net уже очень давно есть WCF и IIS, которые бы решили нашу проблему
                                                                                      4) Закончу на положительной ноте для Java — open source. В той же IntelliJ можно найти имплементацию любого метода и даже в дебаг кинуть. В .net core была подобная возможность, дебажить исходники, но потом почему то убрали и сделали фигню, которая работает только в call stack, а вот если просто нажму open implementation на системном методе, то мне покажет только методанные. Вообщем огромный плюс Java

                                                                                      Если я в чем-то не прав то пожалуйста напишите об этом, буду рад любой информации
                                                                                    • 0
                                                                                      Очень неудобная настройка билдов (maven)

                                                                                      В idea есть maven plugin, который позволяет удобно выполнять частые операции с maven, поддерживает профили и т.д. Файлы xml maven хоть и часто большие, но однообразные и простые по структуре. Это отличается от xml в мире .net, где из-за сложности пришлось сделать графическую утилиту. Как правило в pom копируется зависимость и забывается, idea же при редактировании подсказывает синтаксис и проверяет ошибки.
                                                                                      Как же плохо без дефолтных фреймворков

                                                                                      Вам в помощь Spring Initializr (https://start.spring.io/). Выбрали нужный функционал, который нужен в проекте, нажали Generate и уаля у вас на выходе проект, который сразу запускается и содержит все что нужно.
                                                                                      • 0
                                                                                        Это отличается от xml в мире .net, где из-за сложности пришлось сделать графическую утилиту.

                                                                                        У вас устаревшие сведения. cproj нового образца и маленькие, и простые.

                                                                                        • 0
                                                                                          Да, устаревшие и я рад что сейчас на .net тоже это поменялось. Но я отвечал на комментарий, в котором упоминалась GUI для конфигов, видимо автор комментария переезжал с устаревшей версии
                                                                                          • 0
                                                                                            GUI при этом никуда не делся и прекрасно работает.
                                                                                            Я пользуюсь и тем и другим — смотря что удобнее по ситуации.
                                                                                            Так что у дотнета преимущество в обоих случаях.
                                                                                            • 0
                                                                                              Так что у дотнета преимущество в обоих случаях.

                                                                                              Не у дотнета, а у одной конкретной IDE (VS) над другой конкретной IDE (Idea) в конкретном вопросе (GUI для редактирования конфигов). Да и то преимущество спорное, на любителя.
                                                                                              • 0

                                                                                                Именно что у дотнета.


                                                                                                1. Новый формат cproj — это все тот же msbuild (а не ide), замены которому де-факто нет.
                                                                                                2. "Конкретная IDE" является лучшей и господствуещей на рынке разработки для платформы.
                                                                                                3. Инструменты для явы почему-то никто от самой явы не отделяет — логично и с дотнетовскими поступать так же.
                                                                                      • 0
                                                                                        T4 для .net, очень увеличивает производительность труда и убирает рутину.
                                                                                        • 0
                                                                                          Да, я знаю про jOOQ, но ни разу не видел его использование хоть в чем-то, напоминающем продакшен.

                                                                                          Есть Querydsl, использовал в продакшене и не могу нарадоваться. Ещё есть Jinq, но с ним я только игрался и идея использовать его в продакшене мне кажется сомнительной. Причина — использует сериализуемые лябмды, что накладывает множество ограничений (лучше анализировал байт-код лябмд с помощью какого-нибудь инструментатора/класслоадера).


                                                                                          Возможно потому что это полу-платный новодел без JSR, возможно по другой причине.

                                                                                          JSR не панацея. На спринг есть JSR? А, скажем, для логгирования используют log4j/logback/slf4j вместо стандартного (JSR) java.util.logging.

                                                                                          • +6

                                                                                            Работал с asp еще до того как был .net, потом с monorail, потом с asp.net mvc и asp.net core, тоже недавно перешел проект, где один из сервисов на Java и spring boot, остальные C# asp.net core.


                                                                                            Впечатления в радикально отличаются от впечатлений автора:


                                                                                            VisualStudio vs Idea


                                                                                            • VS (даже с R#) гораздо стабильнее и быстрее чем idea, по крайней мере на моих маленьких проектах
                                                                                            • в VS не нужна кнопка invalidate caches and restart, за много лет использовал сброс кеша R# один или два раза, в idea при переключении веток и редактировании зависимостей gradle регулярно ее использую

                                                                                            при переходе С# => Java очень напрягает:


                                                                                            • отсутствие var, async/await, linq, extension methods и class properties
                                                                                            • местами очень недружелюбный api библиотек
                                                                                            • type erasure, не предполагал что так быстро с ним столкнусь
                                                                                            • checked exceptions, не ощутил пока особой пользы

                                                                                            при переходе asp.net => spring boot:


                                                                                            • аннотации везде и для всего, причем не везде даже с compile time checking
                                                                                            • неявный DI, аннотации для регистрации
                                                                                            • отсутствие nuget install-package и UI к нему

                                                                                            не могу согласиться с:


                                                                                            Впрочем, адекватные альтернативы IIS под Windows от этого не появились (да я знаю про Kestrel для .Net Core).

                                                                                            selfhosted asp.net webapi можно было писать и до .net core, хочешь запускай как консольное приложение, хочешь как win service с TopShelf например, отличный вариант для новых приложений который не зависят от возможностей IIS


                                                                                            Только спустя 15 лет в Микрософт поняли, что это хорошо и пора перестать диктовать миру “как правильно жить”

                                                                                            у меня сложилось впечатление что это в spring boot мне диктуют как правильно жить, как иcпользовать DI, как называть разные lifescope и тд


                                                                                            Я могу написать web-приложение на Java без единой строчки xml (привет Spring Boot), и не могу это сделать на .Net (привет web.config, который “по сути” тот же web.xml, только еще и перемешанный с конфигом).

                                                                                            пара очень простых и легко читаемых файлов в проекте напрягают гораздо меньше чем gradle config, хотя он и не xml

                                                                                            • –1
                                                                                              у меня сложилось впечатление что это в spring boot мне диктуют как правильно жить, как иcпользовать DI, как называть разные lifescope и тд

                                                                                              Так никто же не заставляет использовать Spring Boot, тем более на него нет JSR. Можете использовать любой другой фреймворк, коих довольно много. И это отличается от ситуации с .net, который до недавнего времени был закрытым и фактически был прибит гвоздями к Windows (энтузиасты из Mono не в счет). И хорошо, что сейчас все по другому, но почему бы не сделать этого раньше?
                                                                                            • +2
                                                                                              На самом деле весь спор решается наличием вакансий на ту или иную платформу в вашем регионе. Вокруг меня количество работы на Java стремится к нулю, зато .Net цветет и пахнет.
                                                                                              • +1
                                                                                                Сложно не согласиться, но вокруг меня ситуация прямо противоположная. И у автора статьи, похоже, такая же.
                                                                                                • 0
                                                                                                  Рынок диктует условия. Я в универе яву учил… А потом пошел вакансии смотреть и резко пришлось платформу сменить. Так что мы все тут в одной корзине.
                                                                                              • +1
                                                                                                В статье нет самого главного, чем JVM сильно проигрывает .Net — это Type Erasure.

                                                                                                Подобное в JVM без костылей не сделать:
                                                                                                class Foo: IProcessor<A>, IProcessor<B> {
                                                                                                   void Exec(A arg){
                                                                                                   ...
                                                                                                   }
                                                                                                
                                                                                                   void Exec(B arg){
                                                                                                   ...
                                                                                                   }
                                                                                                }
                                                                                                
                                                                                                т.к. во время компиляции void Exec(A arg) и void Exec(B arg) превратятся в void Exec(Object arg) и мы получаем конфликт между двумя методами с одинаковой сигнатурой. Можно создать явно интерфейсы IProcessorA и IProcessorB в которых будет указана сигнатура, не имеющая generic type аргументов, но этот workaround мешает компоновке библиотек, т.к. появляется зависимость на конкретный интерфейс для конкретного аргумента generic типа (IProcessorA — A). А это значит, что все, кто захотят поддерживать интерфейс IProcessor, должны заранее договориться использовать общую сборку в которой лежит IProcessorA. А теперь представим, что есть N независимых разработчиков, не знающих друг о друге, объявивших в своих библиотеках свой IProcessorA…
                                                                                                Есть решение через полиморфизм, но это в свою очередь осложняет жизнь тем, что в каком-то месте вам нужно указать все поддерживаемые типы-наследники. Что также является антипатерном. В общем, из одной ловушки в другую.
                                                                                                Подробнее тут.

                                                                                                Можно привыкнуть к новой IDE, освоить новый язык, потратить многие месяцы на изучение нового технологического стека, но один лишь факт того, что в языке нет полноценной реализации такой базовой штуки как Generic Types, означает, что постоянно будет ощущение неполноценности разрабатываемого кода, по сравнению с аналогичной реализацией на .Net.

                                                                                                Пробовал программировать на Kotlin (на мой взгляд, у языка прекрасный синтаксис), но описанная выше проблема сводит его преимущества перед C# на нет.
                                                                                                • 0
                                                                                                  постоянно будет ощущение неполноценности разрабатываемого кода

                                                                                                  Это не просто ощущения, а суровая реальность.
                                                                                                  Контейнеры в яве такие страшные (с засилием аннотаций) как раз из-за генериков.
                                                                                                  Нормальных коллекций для типов-значений нет тоже из-за генериков.
                                                                                                  Даже если введут кастомные типы-значения толку от них будет мало опять-таки из-за генериков.
                                                                                                  Все преимущества в производительности от шикарного оптимизирующего рантайма могут быть сведены на нет теми же генериками.
                                                                                                  По ходу автор просто нашел себе нового идола для карго-культа.

                                                                                                  • 0
                                                                                                    Да уж дженерики в яве сделаны отвратительно, я не могу понять почему выбрано такое странное решение.
                                                                                                    • 0
                                                                                                      Обратная совместимость на уровне байт-кода — иначе старые JVM не смогут в новые дженерики, а они дорожат запуском нового кода в рарихетных рантаймах.
                                                                                                      • 0
                                                                                                        а может добавить ключ компиляции и дать возможность мне самому решать нужна ли мне эта обратная совместимость или нет?
                                                                                                        • 0
                                                                                                          Тогда все сразу забьют на поддержку старых версий)
                                                                                                          • 0
                                                                                                            Когда это решение принималось, то это было самым простым решением. Сейчас же менять это уже поздно, и ОЧЕНЬ дорого.
                                                                                                  • +1
                                                                                                    В .NET выбор очевиден — Visual Studio.

                                                                                                    Как же VS Code для .net core? Rider?
                                                                                                    • 0
                                                                                                      «5. Community», а может оно и лучше? Я без слез на прогресс платформы явы на фоне дотнета без слез смотреть не могу.
                                                                                                      • 0
                                                                                                        В высоко нагруженных проектах с mssql и радостным linq, когда начинаешь разбираться в миллионе планов, безумном их трафике и удивительной их параметризации, понимаешь, что это далеко не преимущество и так делать не нужно. Что значит отключать автокоммит инструкции и главное зачем?
                                                                                                        • 0
                                                                                                          Прочитал про LINQ. Интересно, хоть и дико для джависта видеть SQL в переменных.
                                                                                                          • 0
                                                                                                            Там есть другой вариант — использование лямбд, с которыми (если привыкнуть) код запросов становится совсем коротким, хоть и теряет в читабельности.
                                                                                                            • 0
                                                                                                              Почему теряет в читабельности?
                                                                                                              • +2
                                                                                                                Кому-то SQL-подобный синтаксис проще читать, он более «самодокументируемый».
                                                                                                                • 0
                                                                                                                  Любой код самодокументируемый, потому что иначе оно бы не работало.

                                                                                                                  Главное преимущество лямбд — типизируемость. Кто-то использует дапперы и фигачат всё на SQL, только вот гарантировать правильные типы, увы, становится невозможно.
                                                                                                                  • 0
                                                                                                                    Любой код самодокументируемый

                                                                                                                    Очевидно, нет.


                                                                                                                    потому что иначе оно бы не работало.

                                                                                                                    Для того, чтобы код работал, читаемость не обязательна.

                                                                                                                    • 0
                                                                                                                      Ок, не так выразился. LINQ-код не более и не менее понятен, чем аналогичный SQL почти всегда.
                                                                                                                      • 0
                                                                                                                        Может я, конечно, ошибаюсь. Но мне кажется, мы недопоняли друг друга и говорим о разных вещах. Я говорил о том, что есть 2 формата записи LINQ (примеры чисто академические):
                                                                                                                        1) SQL-образный
                                                                                                                        var selectedUsers = from user in users
                                                                                                                                            from lang in user.Languages
                                                                                                                                            where user.Age < 28
                                                                                                                                            where lang == "английский"
                                                                                                                                            select user;

                                                                                                                        2) С использованием лямбд
                                                                                                                        var selectedUsers = users.SelectMany(u => u.Languages,
                                                                                                                                                    (u, l) => new { User = u, Lang = l })
                                                                                                                                                  .Where(u => u.Lang == "английский" && u.User.Age < 28)
                                                                                                                                                  .Select(u=>u.User);


                                                                                                                        Причём запросы могут формироваться, как LINQ for Objects, так и LINQ for Entities. Первое — для коллекций, второе — для ORM, что в итоге преобразуется в банальный SQL запрос для СУБД.
                                                                                                                        • 0

                                                                                                                          И то и то LINQ, просто у него 2 формы записи: query linq и method chain linq. Первый вариант иногда читаемее, а иногда нет. Например типичный запрос выглядит так:


                                                                                                                          var foo = mytable.Where(x => x.Foo == 1).Select(x =>x.Bar).FirstOrDefault()

                                                                                                                          В виде query получается немного нелепо.


                                                                                                                          А я изначально подумал что вы в прямом смысле про SQL в шарпе:


                                                                                                                          var foo = mytable.Query<Thing>("select * from Thing where Name = @Name", new {Name = "abcde" });

                                                                                                                          Насколько это читаемее — вопрос

                                                                                                          • +1

                                                                                                            Джава очень уж многословна по сравнению с шарпом. В нее автопроперти-то завезли наконец?

                                                                                                            • 0
                                                                                                              Недавно завезли var, что должно уменьшить многословность. Автопроперти делаются с помощью аннотации над классом (с Lombok). Но многих это несильно волнует, т.к геттеры и сеттеры генерятся легко в любой IDE.
                                                                                                              • +1
                                                                                                                геттеры и сеттеры генерятся легко в любой IDE

                                                                                                                Претензия не в том, что геттеры/сеттеры сложно генерировать, а в том, что по сравнению с .Net наблюдается увеличение объёма кода. Вместо одной сущности — автосвойства, три — переменная + геттер + сеттер.
                                                                                                                • 0
                                                                                                                  Как я и писал выше, для уменьшения кода применяется Lombok. К классу добавляется аннотация и после этого у всех полей появляются сеттеры и геттеры (при этом в коде класса их явно нет). Если и это напрягает, никто не мешает использовать Котлин )
                                                                                                                  • 0
                                                                                                                    Вплетение байт-кода вместо нормальных языковых средств — магия и костыль.
                                                                                                                    Гоферы с тем же успехом ссылаются на прости господи кодогенерацию.
                                                                                                                    • 0
                                                                                                                      В мире джавы мало кого смущает и генерация сеттеров IDE и Lombok, в котором магии не больше чем в Spring. Но, как уже писал выше, никто не мешает использовать Котлин, которые в обе стороны совместим с Джавой, и в котором есть все что нужно. Но, возможно, сейчас и тут напишут про проблему с дженериками.
                                                                                                                      • 0

                                                                                                                        В дотнете Fody тоже никого не смущает.
                                                                                                                        Но никто не делает вид, что вплетение кода заменяет имеющиеся языковые средства задаром.
                                                                                                                        А котлин мне очень нравится.


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

                                                                                                                        Такова жизнь. В JVM JIT и сборщик мусора лучше дотнетных. Но нет генериков и непримитивных типов-значений.

                                                                                                            • 0
                                                                                                              Больше 2х лет использую JOOQ в банковском (и похожем) энтерпрайзе.