Безкоштовна онлайн-конференцiя з Python від fwdays. 14 грудня. Реєструйся!
×Закрыть

Перехід з С++ (not web related) в Web Backend (Java/C#/Python)

Всім привіт.

Передісторія:
Працював на C++. Писав різного роду backend логіку, чи то для системних процесів, чи то для десктоп аплікацій, одного разу навіть навіть веб сервіса довелось писати (як виявляється для цього в нас плюси не часто використовують). Одним словом спеціалізації в чомусь не було. Вирішив щось міняти. Думати довго не довелось. Web на ринку праці України найбільш розвинений.
Мені ближче тай цікавіше backend, от і вирішив цим займатись.
Після інвестигації використовуваних технологій/мов/фреймворків зупинився на Java (Spring), Python (django) і C# (.Net/.Net Core).

Питання:
Проблем в тому що вони всі маю свої плюси, свої мінуси. Не можу визначитись що буде більш актуально/ використовуване на ринку праці.
Буду вдячний за ваші думки нарахунок цього.

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
упинився на Java (Spring), Python (django) і C# (.Net/.Net Core).

Смотри, что субъективно тебе ближе, то и выбирай, все три области огромны, в них много денег и они будут, фактически, флагманами еще много-много лет

Посмотрите в сторону golang. Это тот же С с синтаксическим сахарком и приправленный аппетитным toolchain.

да вот только к Го еще очень много хотят из микросервисов, знания пачки продуктов Hashicorp, kubernetes, docker; со знаниями одного только чистого Го практически не берут

На других языках у работодателей аналогичные хотелки.

Не знаю, на счёт Java и Python, но в .Net, в большинстве случаев, чистый back-end разработчик бизнесу не интересен.

Поэтому, для .Net, добавляем ещё сверху JavaScript, TypeScript, Node.js, JQuery, Angular, React+Redux, Vue.

Скажите пожалуйста, вы рассматривали Go?

1. Не впевнений, але мені здається що з точки зору бізнесу чистий бекенд девелопер не цікавий напевно і в Java з Python також.
2. Ні, Go не розглядав.

дык можно найти работу, где есть плюсы и еще что-то, так и перейдешь за счет работодателя

где есть плюсы и еще что-то

Мінуси?

Був колись С—, але не витримав конкуренції)

Справа ваша, але поки я собі кодив на плюсах, у вебі й мобайлі все десять разів встигло помінятись. Бекенд, звісно, також потроху еволюціонує, але переливання з пустого в порожнє там якось менше. Можна мати 20-річний досвід Linux, досвід PalmOS чи WinMobile ні в кого й до 10 не дотягнув.

лет 8 назад перешел с C++ бекенд на Java бекенд. Из-за денег :-( . на Java в тот момент были более денежные вакансии и выбор больше. вообще в языках с С-подобным синтаксисом (java, C#, kotlin, scala) много общего, после одного изучить другой — несложно. Python в связке с machine learning сейчас очень хайповая тема и можно денег поднять

А хіба в цепепе програмістів ЗП не більші ніж в веб-макак?

Сильно залежить — широка область і мало люду

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

Как то я ходил на собеседование на джуна c++. Перед этим сделал тестовое. Во время собеседования меня спросили сколько я хочу, я ответил что 800 дол после испытательного. Мне сказали ну опыт у вас есть судя по тестовому, но владелец(который в германии) после многих студентов принятих за 400 дол будет предлагать 600 дол максимум. А мой друг недавно джуном веб программером на 1.1 к устроился. Вот Вам и выше сложность c++ и «больше» зп.
Было это в Киеве года 2 назад.

ну у меня лет 8 назад с 1.5к на с++ получилось перейти на 4к на пшп

даже 2г назад за плюсы 800 это ни о чем вообще. На пыхе можно спокойно говно месить начиная от 1К. Надо было больше контор попробовать

Нет. Зависит от места работы. Если в Штатах, то выше, если в постсовке, то ниже.

Не можу визначитись що буде більш актуально/ використовуване на ринку праці.

це ніхто не знає, по великому рахунку усе буде, хоча із наведеної трійки я думаю у python більше веб майбутнього (хоча мені django не дуже сподобалася, але там наче не тільки django є) — просто тому що динамічно типізована мова , що для веба відносно важливо (на c#/java один і той ж саме функціонал буде банально мати більше байтів у коді, чим на python)

можна ще дивитися на ruby та nodejs, воно теж буде, але я б рекомендував дивитися як мова йде, бо я наприклад, відчував себе не дуже комфортно у python, вже звик до фігурних дужок

п.с. десь років 10+ тому уходив із с++, але мені треба було щоб remoting був і щоб без майкрософт (хоча c# дуже красива мова), після деяких поневірянь (і java була і python) вийшов на highload php, мова найбільш органічно «лягла» після c/c++ ну і в базах, оптимізаціях я знався , навіть міг якийсь extension пофіксити і перезібрати

Ну власне напевно, буде усе.
Просто цікавила думка людей, які мають досвід з Web Backend.
Наразі складається враження, що потрібно обрати будь-яку з них і просто почати роботу з Web Backend (те заради чого ця розмова і почалась).
Проте схиляюсь більше до Java.
Чомусь не покидає враження що Python не надто advanced мова, через що і не можу зрозуміти чому вона краща для цих потреб.

Python надзвичайно зручний та гнучкий порівняно з іншими старими мовами. Там навіть є синдром звикання, коли після кількох місяців на пітоні ніщо інше не кодиться. І писати на ньому в рази швидше та компактніше.

Хіба на великих код бейзах потрібна надмірна гнучкість? А не навпаки — дотримання загальних стандартів і рідабіліті?

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

Чим більше девів — тим важче підтримувати стандарти. І якщо стандарти ці лише по конвенціях писані, то дуже вірогідно що код перетвориться в щось погане. І навпаки — якщо мова допомагатиме писати правильний підтримуваний код — це збільшить кваліті продукту. Крім того, більшість програмістів не вміє писати хороший код, і якщо цій більшості дати гнучку мову, то там буде гнучний спагеті код. Джава для фіксу цієї проблеми і задумовувалась.

Тоді усе потрібно переводити на Раст.

І навпаки — якщо мова допомагатиме писати правильний підтримуваний код — це збільшить кваліті продукту. Крім того, більшість програмістів не вміє писати хороший код, і якщо цій більшості дати гнучку мову, то там буде гнучний спагеті код.

Якщо писати на Расті — то більшості там не буде, а хто залишиться — ті не зможуть писати гнучкий код, бо мова негнучка)

ну ти можеш:
1) перегрузити усі оператори
2) перегрузити виклик метода, щоб перед чи після нього викликалась кастомна функція
3) перегрузити доступ до поля об’єкта щоб замість прямого доступа до даних викликались методи-аксесори
4) перетворити об’єкт на клас, щоб він робив інші об’єкти
5) multiple inheritance з діамантами в 1 рядок коду
і ще купа всього, що я не пам’ятаю

тобто, якщо тобі заборонена арифметика з пойнтерами, то це

мова негнучка

гг

multiple inheritance

і без діаманта

перегрузити усі оператори

напоркуа?

перегрузити виклик метода, щоб перед чи після нього викликалась кастомна функція

WTF

перегрузити доступ до поля об’єкта щоб замість прямого доступа до даних викликались методи-аксесори

тіпо рефлексія?
крім юніт тестів в джабі (де тре через опу рвати гланди) не бачив потреби

Невзирая на всю свою скромность, я думаю что могу написать говнокод на любом языке. К тому же, уже практически везде стоят линтеры и используют CI/CD, если код не соответствует стандарту — можно просто ронять билд. Я все равно считаю, что вопрос выбора языка для поддержки и качества кода — это как выбирать между теплым и мягким, когда тебе нужно круглое.

Компилер должен отлавливать часть проблем с обращением к несуществующим членам классов либо опечаток. Интерпретатор этого не может, так как интерпретирует в момент выполнения ту строчку, которую выполняет. Линтер тоже не может если есть exec с динамическим созданием кода. Либо если взять монстра с перегрузкой всего типа Джанго — думаю, там распарсить происходящее тоже будет грустно.

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

для цього є тести

Бачив 100% покриття логіки тестами?
А якщо поле об’єкту динамічно створюється в одному місці коду, а використовується — в іншому? Якими тестами покриєш: юніт- чи інтеграційними? Інтеграційні тести пишуть усі програмісти коли змінюють щось в своєму коді?

Бачив 100% покриття логіки тестами?

коли паблік апі — так, якщо не тестами , то use cases
ну і взагалі, у реалі майже не зустрічав помилок, про які ви пишете, тобто вони виникають (і то, з усіма цими code completion дуже рідко) , але навіть на етапах попередньої перевірки розробником проявляють себе , ну тобто я написав щось, запустив, отримав помилку — виправив. у прод і далі таке не попадає

Запуск не завжди покаже помилку, а компіляція завжди, якщо це не рантайм баг. То навіщо

на етапах попередньої перевірки розробником

Якщо це саме зробить компілятор набагато швидше і глибше? Одне натискання кнопки і вся твоя код бейз провірена. Крім того оці явні типи потрібні не лише для компютера, чи провірки на баги, а й для програміста, щоб В ПРОЦЕСІ написання коду він бачив що саме очікує від нього метод, який програміст хоче використати, і що той метод повертає, і щоб айді моментально вказала на помилку типу.

Запуск не завжди покаже помилку, а компіляція завжди, якщо це не рантайм баг. То навіщо

але запускати ви будете завжди, просто помилка виявиться на іншому етапі, а за рахунок відсутності компіляції, та додаткових витрат часу на прописування типів — помилка банально виявиться швидше :)

В ПРОЦЕСІ написання коду він бачив що саме очікує від нього метод

якщо ви пишете документацію до методів, то там і буде ця інформація , навіть більш детально, ніж в декларації метода

помилка банально виявиться швидше :)

Повна маячня. Чим пізніше виявляється помилка тим більше вона коштує. Так в одній книзі писало.

та додаткових витрат часу на прописування типів

Ппць.

якщо ви пишете документацію до методів, то там і буде ця інформація , навіть більш детально, ніж в декларації метода

Святі корови. Тобто тип всерівно прийдеться написати, але він ні на що не вплине? Начихуа?

Повна маячня. Чим пізніше виявляється помилка тим більше вона коштує.

отож. у нетипізованих мовах вона виявиться раніше

Святі корови. Тобто тип всерівно прийдеться написати, але він ні на що не вплине? Начихуа?

для програміста, це може бути не просто int, а int в діапазоні (наприклад), або не просто строка, а json

отож. у нетипізованих мовах вона виявиться раніше

Це якась альтернативна логіка блондинки?

це може бути не просто int, а int в діапазоні

І тоді треба провіряти валідацією, а не покладатися на документацію, яка одразу застаріває і яку ніхто потім не читає. Взагалі код має бути таким, щоб по сигнатурі зрозуміло що і як. І до речі, інт в діапазоні все ще інт.

не просто строка, а json

В такому разі це вказується в назві методу чи аргументу. А взагалі, json не ганяється між методами всередині апу. Він створений для передавання інформації між сервісами через хттп протокол(або ж зберігання в файлах). Після отримання дані одразу ж переводяться в зрозумілий для апу формат — об’єкт.

int в діапазоні

enum зветься

не просто строка, а json

візьми розпарсь зразу при отриманні в окремий тип. нащо тобі нерозпаршений json?

enum зветься

Думав написати. Дякую що доповнив)

візьми розпарсь зразу при отриманні в окремий тип. нащо тобі нерозпаршений json?

ну наприклад нещодавно ключ від gcloud так передавався, сенс його парсити, якщо він так і передається в апі
cloud.google.com/...​ging-service-account-keys

Оберни його в окремий клас, щоб ніхто не почав його міняти. В С++ є ще typedef
typedef const string AccountKey;

Оберни його в окремий клас

це те, про що я кажу. типізовані мови вимагають більше кода, ніяк не підвищуючи якість кода

Признайся, на типізованих ти писав лише в універі? Інакше все погано, дуже погано.

наразі це не є загальновживаною думкою, бо не усе перейшло на пітон

Проблема в його логіці в тому, що він видає додатковий захист, при чому опціональний, який дозволяють робити типізовані мови, як недолік типізованих мов. Ніхо не забороняє не огортати в окремий обєкт, можна писати як і на динамічній, і в назві методу або ж і в документації до методу пояснити що тут сувати інт ренж(wahtever). Динамічна ніяким чином не робить цю проблему легшою.

А сенс тоді його(тип параметру) документувати, якщо він використовується як string і ніяк не розпарсюється твоїм апом? Сам себе загнав в глухий кут.

не розпарсюється твоїм апом?

бо інший розробник , який визиває цю функцію, буде знати що там передавати. і ніякий компілятор тут не допоможе

Спитаю ще раз. Маємо метод, який отримує ключ гугла. Яка нам різниця в якому форматі ключ гугла, в якому хешуванні, якщо той ключ використовується лише як ключ без додаткового динамічного навішування до нього даних? Ключ передається типом стрінг. Все, що треба знати деву, який використовує цей метод, це те, що йому потрібно впихнути ключ, і той ключ ще в форматі стрінг. Той дев не будує джейсон, він його бере із файлу конфігурації апу. Все.

Сенс в тому, щоб коли Гугл змінить формат ключа, чи коли контора переїде з Гугла на Мікрософт, не переписувати весь код, котрий в Гугла зберігав чи приймав рядок, а в Мікрософта — інт64.

Так це нам забезпечить стандартна типізація. Тип стрінг і інт відрізняються. Ще на етапі компіляції викине помилку. А якщо переїжджаємо де в одному ключ джейсон, а в іншому результат хеш функції, то оба є стрінг і все буде так само працювати.

Коли треба переїхати на інший тип, добре, коли цей тип в одному місці названий окремою назвою (typedef). Тоді весь код, де він трапляється, не потрібно переписувати, а просто один раз змінити typedef.

а просто один раз змінити typedef.

ех, були часи коли іноді після такої простої зміни хедера, потім дві години чекав поки воно перекомпілюється :)

чтоб нельзя было сунуть произвольную строку например

Так чи інакше, дев візьме той ключ з файлу конфігу(і більше нічого з ним не буде робити), і вже завдання провірки ключа, лежить на сервісі гуглу, на стороні приймання реквесту. Джейсон може бути правильний, а дані в ньому застарілі. Тоді всерівно видасть помилку. А якщо ми використовуємо сервіс, в який треба годувати дані в json форматі, то перетворення даних в json має робити внутрішній хелпер методу, а не клієнт. Клієнту винести зрозумілий тип даних на вхід, чи то декілька варіабл з різними типами, чи то клас з тими ж варіаблами. Клієнт коду не має власноруч будувати чи конвертувати в JSON формат.

Ми трохи зійшли з рейок. Я писав про те, що в стронг мові вже є достатнім наявність базових типів. А мій опонент з когорти скриптовиків розказував що ні, це буде недостатньо. Але ж якщо це недостатньо в стронг мові, то тим паче буде недостатнім і в вік мові. Зрозуміло що в динамік потрібно якимось чином дати знати що нам потрібен ключ типу стрінг, наприклад. І в обох, можна додатково коментнути, або в стронг мові клас для цього типу створити і все буде ідеально валідувати.

enum зветься

ну може щось змінилося, але раніше enum такі речі, як наприклад вік людини, або zip не дуже :)

а який ренж у віку?
typedef знову ж

Яким чином документування методу убереже від передачі неправильного віку людини? А як зветься метод? З його назви не зрозуміло для чого той використовується? Слово «Age», ні?

Якщо все настільки погано, то є варіант з обертанням в клас, як запропонував Денис. Є навіть такий патерн, зветься Value Object Pattern. Якраз для подібних речей. І до речі без типізації він не допоможе, бо тут потрібен тип класу в сигнатурі методу. Азаза.

Слово «Age», ні?

вже з’явився компілятор, який має тип age ? :)

Перезапусти свій інтерпритатор і почитай мій коментар ще раз.

Ти не повіриш... але компілятору не обов’язково «мати» тип, достатньо щоб система типів була достатньо гнучкою щоб його описати.

type Age = Not[Less[0]] And Less[150]
type AgeInt = Int Refined Age

// це скомпілюється
val age1: AgeInt = 0
val age2: AgeInt = 10

// а це — ні
val age3: AgeInt = -1
val age4: AgeInt = 150

і навіть
val age5: AgeInt = request.input('price').toAge();
скомпілюється, але потрібен буде запуск програми і тести, щоб впевнитися що все працює
я ж про те, що те, що успішна компіляція ніяк не доводить що програма без помилок

Фейспалм. У вас інпути без валідації проходять?

я про те що компілятор допомагає не там, де воно реально потрібно

Валідація може буть кривою.

То хто винен, що вона крива? Компілятор? Ну отримає змінна дефолтне значення при байдингу: 0, і запишеться в базу вік 0.

І тому бойлерплейт типу

request.input(’price’).toAge()

взагалі непотрібно писати. Він має автоматично генеруватися з моделі даних. При чому інфа з рефайнед типу буде використана для валідації.

Передбачаючі наступний аргумент — якщо в моделі у вас написано, що price: Age — то тут дійсно ніякий компілятор не врятує. Так саме як і коли знайдеться 150 річний юзер :) Але це вже баги не у програмі а у спеціфікації.

якщо в моделі у вас написано, що price: Age — то тут дійсно ніякий компілятор не врятує.

дякую. весь цей тред був присвячений відповіді на

Компилер должен отлавливать часть проблем с обращением к несуществующим членам классов либо опечаток.

Проблема в тому, що proger не розуміє різниці між компайл тайм ерор і рантайм ерор. Рантайм ерор по своїй суті не може бути зловлений компілятором, тому що на час компіляції незрозуміло що саме прийде в програму. Якщо програміст не ловить ексепшин при байдингу(взагалі фреймворк сам це хендлить) щоб потім задати типу дефолтне значення, або ж повернути validation failed, то це вина програміста, так як і відсутність валідації вхідних даних. В динамічній мові ексепшину не буде, зате буде хибне валю, яке так само прийдеться прогнати через валідацію, інакше завалиться далі щось(або вийде хибне обчислення, що взагалі неймовірне важкодіагностуєме зло). Proger би ще звинуватив компілятор що той від sql injection не захищає. Повна відсутність компетенції в питанні.

Як раз від SQL injection — компілятор може і захистити ... якщо ліба для доступу до бази не дозволяє пихати в себе квері у вигляді RAW строк — тільки типізовану структуру, у якій всі змінювані будуть правильно заескейплені перед відправкою у базу.

Правдиво для типів інт і т.д. А стрінг яким чином загнеться якщо в нього засунуть неекранований рядок? В результаті ліба ж всеодно генерує звичайну sql команду у форматі стрінг.

Ну... либа должна ещё поддерживать все фичи базы, может я захочу какой-нить хинт оптимизатору прокинуть... Также грустно, когда уязвимость находится в самой либе...

Взагалі будь-який динамічно типізований код — можно описати за допомогою якоїсь сістеми типів. З різною деталізацією в залежності від того — що ця система типів дозволяє описати. Просто у динамічній мові ніхто ці типи не бачить.

Можна сказати, що виконання динамічно типізованної програми — це теж тайпчекінг тих типів ... але він виконується у рантаймі та тільки для тих гілок, що таки були виконані. Ну і баги у якійсь рідко використовуваній гілці, яка чомусь :) не була покрита тестами ловить вже користувач.

Ну і баги у якійсь рідко використовуваній гілці, яка чомусь :) не була покрита тестами ловить вже користувач.

ця проблема існує без залежності від типізованості мови

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

не дозволяє пихати в себе квері у вигляді RAW строк

так ці ліби не те що давно вже існують, а обов’язкові для використання як для типізованих, так і нетипизованих мов

Тільки в типізованій в інт не просунеш стрінг, а в нетипізованій просунеш, і ерор вилізе пізніше на етапі виконання sql.

так само прийдеться прогнати через валідацію

отакої, я про це і кажу вже десять коментів

Если вот прямо проект аж дохреналиард строк обмазанных магией — то для такого есть mypy, пишешь себе аннотации и оно проверит. Вопрос в том, сколько вообще существует таких проектов, где это необходимо.

Наверное, их на Питоне потому и нет, что неудобно. На Джаве овердофига, на С++ тоже много.

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

На будь-якому проекті рівня не хело ворлд(тобто кожен перший ап), таке потрібно.

Та ну. Прототипи, скрипти для парсінгу логів, сторінки інтернет-магазинів, скрипти в іграшках чи 3Д-рендерерах...
Усе, що при падінні не звалить дорогу систему, і що не має біжати 24/7

Усе, що при падінні не звалить дорогу систему, і що не має біжати 24/7

Окей, але річ не лише про незвалювання, а й про зручність розширення функціоналу. Коли усе типізовано то легше розібратись і дописати.

Сама типізація займає час. Думаю, що скрипт на 1000 рядків Пітона перетвориться на 2000 чи 3000 у джаві чи С++. Тому таке швидше й зручніше писати на Пітоні, і якщо нормально написане — то й розібратись не проблема буде незалежно мови.

Ви дивите на речі з висоти джави і плюсів, а я з шарпу. В шарпі все компактно пишеться, і швидкість написання від динамічної ніяк не відрізняється. Окрім того що в динамічній можна наговнокодити як попало(до прикладу напихати в один метод декілька ретурн типів що є порушенням Single Responsibility Principle). Але це не зовсім той результат який треба) Хоча брешу, в шарпі теж так можна, якщо вставити тип dynamic =)

Чомусь не покидає враження що Python не надто advanced мова, через що і не можу зрозуміти чому вона краща для цих потреб.

Тут не про розмір проекта, а про мову. Мова дозволяє перевантажувати усе, від операторів до доступа до змінних об’єкту до перетворення об’єкту на клас. І підтримує множинне наслідування в один рядок «з коробки».

А те, що великі проекти треба писати на компільованій мові — то усі діти знають)

Мова дозволяє перевантажувати усе, від операторів до доступа до змінних об’єкту до перетворення об’єкту на клас. І підтримує множинне наслідування в один рядок «з коробки».

Тобто мова дозволяє написати більш заплутаний код з купою сайд ефектів? Сумніваюся що це перевага, якщо річ про більші проекти. Звісно, коли посадити 10 пітон хакерів, то вони напишуть грейт софтваре. Але ж скільки тих хакерів у порівнянні з всією популяцією девів?

А те, що великі проекти треба писати на компільованій мові — то усі діти знають)

Та фіг зна, що і де і хто знає. Якщо погуглити, то там навіть на питання «Чи варто написати ОС на пхп» відповідять «Why not». Я не знаю хто підтримує адекватність інженерну в цьому хайповому болоті веб девів 23-річних сеньйорів.

Тому на Пітоні здебільшого пишуть вспоміжні скрипти та інтернет-магазини. Джанго розробили для швидкого додавання кастомних сторінок з новинами, здається. В ентерпрайз, звичайно, його не пхають.
Але коли требе якийсь прототип — навряд чи буде варіант написати швидше на іншій мові.

Инстаграм и дискас вроде как не согласен, что джангу в прод не пихают.
Кстати аналитика на миллиарды событий в каком-то из сервисов фейсбука написана на питоне и asyncio.
upd. Bitbucket тоже юзает джангу

Джанга в проді з свого народження.
Я про те, що коли проект від мільйону рядків коду, то туди треба компілятор, бо якщо десь не та літера стоїть, і такий монстр через це навернеться — то буде дорого коштувати.

я теж цього боявся, але виявилося що такої проблеми немає, і не має bloated синтакса, де третина коду присвячена тому, щоб розповісти коп’ютеру що строку треба зберігати як строку, а масив — як масив :) а потім ще й явно преобразовувати усе у строки (якщо ми про веб)

var в C#

а потім ще й явно преобразовувати усе у строки (якщо ми про веб)

Цим займаються вбудовані бібліотеки.

var в C#

так. це трохи полегшує, але у декларації функцій чи преобразуваннях все одне треба писати, toString чи що там

? Помоєму це логічно що в деклараціях методів потрібно вказувати що повертається і що приймається. В цьому і суть сильної типізації, щоб забезпечити вірність інтерфейсу і реалізації.

деклараціях методів потрібно

для public методів — так, я так і роблю через type hinting (у php), але private методи, або якісь ну зовсім зрозумілі параметри — id, name ....

Неймовірно, до пхпшників потроху доходить.

Неймовірно, до пхпшників потроху доходить

ну коли закінчуються логічні доводи, починається ... гг

Пхп і логіка ... гг

ну я на php останні 10 років, а до цього лише на типизованих мовах, паскаль, c++, с#. і (передаючи вітання даннінгу крюгеру) раніше вважав так як ви
так що знайдіть час для свого розвитку, подивіться що у світі (розробки) відбувається, воно корисно для мізків.

Мене не цікавлять ваші особисті проблеми. Те що ви після нормальних мов перейшли на пхп, говорить лише про те, що ви до пхп щось серйозне таки не програмували. Але знову ж, це мене не стосується.

По моему с версии 3.6 в питошке — спокойно пихаешь аннотации и кормишь это все в mypy. И получаешь свои декларации. Только в очевидных или не критичных местах можно не писать тайп хинты.

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

А есть пример где вот без типипизации апи выглядит прямо ужасно?

великі проекти треба писати на

джаві або Сшарпу

А як же Го? Го го го? Ні? Го???

А що дуже велике на ньому написане?
Го вже в ентерпрайзі?

в виде микросервисов — вполне. А здоровый монолит на нем писать — чуть лучше, чем на С

docker, почти все продукты www.hashicorp.com, kubernetes... Энтерпрайзные решения

дотримання загальних стандартів і рідабіліті?

вже давно люди користуються усякими тулзами, які перевіряють код на стандарти і рідабіліті (навіть, я вибачаюсь, у php гг)

От доречі, пітон це єдина популярна мова, де є обов’язкові відступи і не напишеш весь файл 1 стрічкою :)

бов’язкові відступи

мені до речі це і не сподобалося в python — не там додав пусту строку — усе, логіка зіпсувалася (я не пам’ятаю деталей, але щось таке було)

ну java це усякий банківський софт і таке інше — дороге і корпоративне, якщо ви себе там бачите — то тоді java, hibernate і фабрики-фабрик-фабрик :)

Чомусь не покидає враження що Python не надто advanced мова, через що і не можу зрозуміти чому вона краща для цих потреб.

Неймовірно адвансед. з величезною екосистемою. В усіх топах за популярністю. Раджу.
Сам свічнувся з с,с++ колись.

Питання:
Проблем в тому що вони всі маю свої плюси, свої мінуси. Не можу визначитись що буде більш актуально/ використовуване на ринку праці.
Буду вдячний за ваші думки нарахунок цього.

Відповідь проста: вчи що подобається. Всі три мови програмування мають достатню популярність щоб знайти хорошу роботу, а також мають хороші перспективи. Пітон звісно найбільше набирає популярності(але чи в вебі теж? чи за рахунок нових областей?), але там більш рапід девелопмент наскільки я знаю. Фігак фігак і в продакшин. А в джаві і шарпі можна буде на великому проекті пописати різні архітектурні штуки.

www.tiobe.com/tiobe-index
pypl.github.io/PYPL.html

Крім того не варто забувати що пітон є скриптовою мовою з усіма плюсами і мінусами(для сішника скоріше мінус).

Ты уверен что питон скриптовый язык, а не интерпретируемый?

хз

The term „scripting language” is also used loosely to refer to dynamic high-level general-purpose languages, such as Perl,[2] PowerShell, Python, and Tcl[3] with the term „script” often used for small programs (up to a few thousand lines of code) in such languages, or in domain-specific languages such as the text-processing languages sed and AWK.

для сішника скоріше мінус

в чому мінус для Сника в пітоні?

За шарп и джаву ничего не могу сказать, но если ты решишь врываться в питон, то посмотри повнимательней — сейчас волна хайпа на асинхронные фреймворки(хотя джанга с версии 3.0 вроде тоже должна будет поддерживать, но там пока мутно все) и DS/ML, так что чистой джанги не так и много по моему мнению.

сейчас волна хайпа на асинхронные фреймворки

Зачем какие-то асинхронные приблуды вроде ноды, когда есть нормальный многопоточный Go, с самой простой реализацией многопоточности.

Раз ею пользуются — значит кому-то или для каких-то задач она удобнее.

Не знаю не пишу на ноде.*Все дальше сказанное исключительно субъективное мнение*. Не знаю на счет ноды, питон тупо удобней и количество реальных задач с которыми я сталкиваюсь и в которых го показал бы значимый прирост в производительности стремятся к нулю. Переписать какой-то «высоконагруженный» сервис на го — я бы лучше взял раст чисто из-за хайпа.

Да, нода это подыхающий труп, в который всеми силами пытаются вкрутить пародию на многопоточность с кучей костылей в виде промисов, колбеков, воркеров с генераторами впридачу

В том то и дело, что асинхронность это уход от многопоточности. Ты получаешь выполнение в один поток с переключнием контекста, поэтому синхронизировать выполнение становиться в разы проще. Это очень удобно, особенно когда 90% нагрузки всё равно ляжет на базу.

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

Асинхронность тут не причём, в таком духе легко можно писать и в многопоточных приложениях. Основное отличие примерно такое: в многопоточным приложениях может выполняться одновременно разные участки кода на разных ядрах, в то время как в асинхронном код выполняется строго в один поток. Также переключение контекста в многопоточном приложении может произойти в любой точке кода, в то время как в асинхронном приложении в строго определенных местах. Обычно такие места даже помечены в коде через await.

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

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

Соответственно, при асинхронности у нас меньше забот с синхронизацией, нам не надо думать, какой мьютекс, атомарную операцию или ещё что заюзать, чтобы вставить элемент в общий список или дикт, потому что мы твёрдо уверены в том, что никто другой в этот момент не может с ним работать.

Есть простой подход позволяющий избежать лишней синхронизации: создавать только константные объекты (read-only). Если проанализировать код, в подавляющем большинстве случаев результат вычисления выражений — в дальнейшем не меняется, за исключением разве что счётчиков циклов, которые можно менять атомарно. Если нужно изменить объект — создаётся новый на основании предыдущего. Кроме того, можно работать с каналами, и писать код который выглядит как асинхронный. Хотя реально на самом деле операции могут выполняться многопоточно на уровне ядра или библиотеки.

Скорее два канала позволяют реализовать концепцию сопрограммы (короутины). А вот асинхроность ближе к кооперативной многозадачности.

Ну... Например, у нас есть сервис, который считает число запросов и трафик от определённого пользователя. После чего читает запрос с другого сервера и возвращает ответ обратно. Время отвремени статистика агрегируется в базу.

В асинхронном случае нам не надо беспокоиться о том, что доступ к stat.request_count и stat.in_bytes был как-то дополнительно защищён. Мы спокойно напишем

stat.request_count += 1
stat.in_bytes += request.content_size
при агрегации статистики, а нам немного придёться вспомнить о синхронизации при записи в базу:
sql = f'INSERT INTO stats(request_count, in_bytes) VALUES ({stat.request_count}, {stat.in_bytes})'
stat.request_count = 0
stat.in_bytes = 0
await execute_sql(sql)
Тут главное не обнулить статистику после выполнения запроса, потому как в этот момент может прозойти переключение контекста await придёт новый запрос, которые не попадёт в статистику.

Без асинхронности нам не обойтись без блокировки, ИМХО:

{
  lock()
  defer unlock()
  stat.request_count += 1
  stat.in_bytes += request.content_size
}

и

request_count, in_bytes := func() {
  lock()
  defer unlock()
  request_count := stat.request_count
  in_bytes := stat.in_bytes
  stat.request_count = 0
  stat.in_bytes = 0
  return request_count, in_bytes
}()
sql := fmt.Sprintf("NSERT INTO stats(%d, %d) VALUES ({stat.request_count}, {stat.in_bytes})", request_count, in_bytes)"
// execute sql

А как ты предлагаешь?

Вышеприведённая схема с локами — это самый простой и эффективный способ, здесь придумывать что-то ещё — это лишнее. Разве что INSERT с форматированием запроса отправить в отдельной горутине. Соптимизировать можно следующим образом: преобразовать логику так, чтоб изменялось только 1 число, которое можно апдейтить атомарно, и поскольку запросы с обнулением выполняются редко, то реально потоки лочиться не будут. Эта схема будет иметь смысл для высоконагруженного сервиса с обработкой bigdata, иначе можно действительно не заморачиваться с локами, если это сложно, и писать асинхронный код под ноду.

Ну... одно число надо упаковать, распаковать. Надо атомарно обнулять, тут уже будет атомарное сравнение с обменом в цикле. Это плюс дополнительный неочевидный код. Плюс думай, лучше нам блокировку свою на пользователя, или эскалировать до общей для всех. Причём ошибиться достаточно легко, а поймать ошибку сложно. Тут особняком стоит Rust, который просто не позволит скомпилировать ошибочный код. В любом случае это дополнительные вопросы, которые требуют решения, квалификации программиста, в отличие от «написал и забыл».

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

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

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

«зеленими нитками», ти про це?

Заставь го работать только на одном ядре, будет тоже самое

Для django треба розуміти HTML+CSS — бо власне веб сторінки він також створює. На Джаві є шанс потрапити в ентерпрайз і взагалі не мати справу з вебом, а займатись лише бізнес логікою.

Для джанги не нужно понимать html и css, понимать фронт хотя бы на элементарном уровне нужно в принципе, независимо от фреймворка. На джангу одной командой накатывается рест фреймворк и можно забыть о хтмл и цсс, отдавая эту дичь полностью на фронт.

Зачем вам фронт, если от вас требуется обычное вэб апи? Лучше уделить больше времени на стандартизацию воркфлоу, предсказуемость сигнатур и удобство моделей.

Подписаться на комментарии