Pull to refresh
1
0.3
Send message

В некоторых компаниях / командах - да, давно :)

Логика примерно такая, что есть например handle "/forum/post/<id>", и есть соответствующая функция-handler, отвечающая за обработку handle. В каком-то смысле этот handle соотносится с дескриптором, тоже дескриптует, за что именно он отвечает.

И да, некоторые компании / команды это ещё и переводят как "ручка".

Да ладно вам, как будто на английском так нельзя: handle (API endpoint) и handle (descriptor). Может быть даже handle handle

А вот "поток" от "потока"(?), увы, отличить не получится.

Вообще-то получится, если есть хоть какой-то контекст:

  • поток-thread запускается / выполняется / останавливается;

  • поток-stream открывается / читается-пишется / закрывается;

  • поток-flow... не очень уверен, наверное проектируется.

А совсем без контекста и более привычные понятия не всегда получится отличить, например "терминал был пуст" - какой ещё терминал? Аэропорт без человек? xterm очистили? Терминал оплаты с экраном без надписей? Терминал-разъём, в который не воткнули провод?

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

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

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

Если в голове нет понимания того для чего нужен vim именно тебе, то и трогать его не нужно, писать комменты и глумится над людьми тоже бессмысленно.

Эта (как и многие другие похожие статьи) страдают обратным: автор настойчиво высказывает мысль, что vim - это объективно хорошо, а всё остальное - плохо. Иногда явно, иногда завуалированно, иногда просто глупо (как вот это "Сделает ли меня более компетентным разработчиком использование Vim? — Да, я могу это гарантировать" в конце).

А, ну и засилье подобных статей. Попробуйте написать статью "Как я перестал бояться и полюбил VS Code / IDEA / Qt Creator / Eclipse / Notepad++"... или нет, просто представьте, что вы увидели такую статью здесь на Хабре. Ну перешёл человек с X на Y, и что, об этом всем рассказывать надо? А вот vim-любители рассказывали и продолжают, хотя те же emacs-любители так себя не ведут (интересно, почему?)

Rust как таковой здесь не важен, просто это единственный пример, для которого у меня есть актуальное время полного запуска LSP-сервера.

Если ваш LSP-сервер делает чуть больше, чем простую подсветку, он тоже будет тратить на анализ при запуске какое-то время. Просто берите проекты больше и больше, и в какой-то момент он тоже будет думать десятки секунд.

Впрочем, некоторые LSP (по ощущениям) при запуске как раз почти ничего не делают, зато потом на каждое действие тратят заметное время. Это ещё сильнее "компенсирует" скорость запуска редактора/IDE, потому что происходит многократно.

Из личного опыта: VS Code открывает средних размеров проект на Rust порядка 3-5 секунд, затем секунд 40 "думает" rust-analyzer. Пока проект анализируется, VS Code продолжает загружать другие плагины, но всё равно rust-analyzer фактически основной, пока он не закончит анализ, я редактировать исходники не буду.

Если бы VS Code запускалась мгновенно (или если бы это был vim/emacs/whatever, запускающееся "меньше секунды"), rust-analyzer всё равно бы думал те же 40 секунд, потому что это время зависит только от самого rust-analyzer и размера проекта, а не от того, какой клиент сидит на другой стороне LSP.

Разница между 40.x секунд и 45 уже не столь существенна, как между 0.x и 5, не правда ли?

вас не переубедить и меня никто не сможет переубедить

...

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

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

Кому-то нравится панель задач размещать сбоку, а кто-то наоборот рад, что значки можно разместить по центру, а не на вполоборота головы, в углу этого самого сумермегаширокого 150:2 экрана.
Кого-то раздражает, что "обычное" меню правой кнопкой теперь урезано и надо кликать с Shift, а кто-то рад, что теперь там только основные пункты, а не десяток "добавок" от сторонних программ, которые нужны раз в год... К тому же, и в Win 11 программы тоже могут добавлять пункты в "короткое" меню, тот же Notepad++ ведь сумел.

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

- Мариванна, почему вы мне это подчеркнули как ошибку, ведь Есенин/Маяковский/Шолохов/Какойтотамский именно так писали!
- Это авторский стиль.
- У меня тоже авторский стиль!
- У тебя - нет, ты не автор. Как станешь известным автором, тогда и сможешь так писать.

До сих пор хочется таких учителей орфографическим словарём огреть.

Я даже не знал, что в Java такое добавили, единственный Java-проект с которым я взаимодействую (как разработчик) до сих пор на Java 8...

Когда я писал комментарий, я имел в виду switch-case как он есть в C, умеющий только сравнивать одно значение за ветку (то есть не pattern matching а value matching). Но конечно же никто не запрещает оставлять имеющиеся ключевые слова при наращивании возможностей.

Вопросов к статье... несколько, но ограничусь двумя:

  1. А точно ли Material Icon Theme упрощает работу и/или повышает производительность (как заявлено в шапке статьи), оно же всего лишь меняет иконки файлов/папок в Explorer view. Если да - тогда докинули бы и пару глобальных тем, потому что оформление самого кода точно влияет сильнее, чем список файлов. Мне, например, нравится Bluloco Light (вариант Italic), хотя Bluloco Dark тоже неплоха (но я предпочитаю светлые).

  2. JavaScript Debugger, который вы рекомендуете - это Nightly версия (на скриншоте даже видно). В базовой поставке VS Code уже есть встроенная релизная версия, убедиться можно если в списке расширений в поле поиска набрать @builtin.

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

Эээ...

Вот у нас есть проект программы, решающей уравнения. Функция решения квадратного уравнения написана в соответствии с алгоритмом от штатного математика, он единственный "ответственный". В целом проект насколько наSOLIDоленный, что сам Мартин бы расплакался от счастья (если бы знал про него, конечно).

Прекрасным сентябрьским днём в проект наняли отдельного дискриминантооптимизатора, чтоб ускорить решение, но через два дня уволили (потому что не надо приходить пьяным и материть одного из верхних менеджеров, он обижается). Код решения за всё это время не был изменён, просто не успели.

Правильно ли я вас понимаю, что сначала код удовлетворял SRP (а значит и SOLID в целом), затем нет, а затем снова да, несмотря на отсутствие изменений?

смысл в таких принципах же как раз в том что они должны давать достаточно четкий критерий.

Пример с SRP на словах, считаем действия, выполняемые функцией. Два варианта:

  1. Функция получает на вход коэффициенты a,b,c квадратного уравнения, и возвращает массив с уникальными вещественными решениями.

  2. Функция получает на вход коэффициенты a,b,c квадратного уравнения, считает дискриминант, определяет количество уникальных вещественных корней, считает эти корни, и наконец возвращает эти корни в массиве.

В первом случае она как будто бы делает одно действие, а во втором - аж четыре (!), хотя алгоритм абсолютно один и тот же. Но в первом случае "на слух" SRP соблюдён, а во втором надо разбивать на 3 части (см solve_quadratic ). А действительно ли это нужно? Да, в функции выполняется более одного шага, и отдельные микрофункции действительно будет проще обмазать тестами, но зачем? Решение квадратных уравнений - элементарный алгоритм, который буквально проходят в школе, да ещё и потом решают десятки если не сотни этих уравнений. Тем не менее, если фанатично следовать SRP - да, нужно разбивать, потому что Дядюшка превыше здравого смысла.

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

Насколько мне известно, это как раз и называется "не объективный". Объективные метрики могут быть измерены по чётко известной процедуре. Например, вычислительная сложность алгоритмов - есть и теоретический подход со всеми этими прекрасными O(n log n), и можно наделать практических тестов. А как измерить единственность ответственности?

А если вернуться к предыдущей цитате, то ещё забавнее получается. В текущий момент времени мне не надо иметь решение уравнения отдельно от печати - то есть YAGNI и KISS говорят, что дробить не надо (потому что больше функций - это не нужно и сложнее), а SRP - что надо. В итоге счёт 2:1 не в пользу SRP, бууу, принцип-неудачник?

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

В моём раздробленном примере выше:

  • функции print_0_solutions, print_1_solution, print_2_solutions следуют SRP, но они малы до состояния замусоривания

  • get_number_of_solutions имеет более одной причины быть переписанной (замена аргумента с дискриминанта на коэффициенты уравнения, добавление поддержки уравнений 1,3,4 степени, добавление поддержки комплексных чисел), то есть она не следует SRP - как разбивать будете?

Когда дядька-токарь, 3D-принтер, или станок с ЧПУ делают детальку, они знают, что эта деталька уйдёт в полностью спроектированное изделие, где все детальки подогнаны друг к другу по размерам и характеристикам. А когда дядька-программист делает функцию - он не знает, через сколько лет, месяцев, или даже дней требования к этой функции изменятся.

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

А вот в программировании не так: сегодня вам сторонний API возвращает в JSON

массив объектов
[
  {
    "a": 1,
    "b": "qwe"
  },
  {
    "a": 2,
    "b": "asd"
  }
]

а завтра этот же самый массив

положат в объект-обёртку
{
  "data": [
    {
      "a": 1,
      "b": "qwe"
    },
    {
      "a": 2,
      "b": "asd"
    }
  ]
}

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

А потом может понадобится получение решение уравнение не только там. ну и в других местах.

Именно поэтому я написал "Вроде логично разбить на 2 подфункции: решение и получение численных ответов, и печать".

От функций код не станет менее нечитабельным

Опять-таки, всё дело в количестве, самостоятельности и возможности переиспользования этих функций.

Вот, в моём раздробленном примере выше:

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

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

  • print_0_solutions, print_1_solution, print_2_solutions - вы точно уверены, что в этих функциях-однострочниках есть хоть какая-то польза? Если вы завтра добавите поддержку уравнений вплоть до 4-й степени - вы напишете 5 таких однострочников? А если до 1000-й степени (не в общем виде, но это уже чисто алгебраический вопрос)? В какой момент вы решите, что надо вместо этих микрофункций использовать цикл по решениям и библиотеку, склоняющую слово "корень"? Но ведь это новое решение будет слишком сложным для квадратных уравнений, поэтому прямо сейчас пусть будет как есть (KISS)?

Дробление на функции - это как дробление чека в магазине: купить упаковку акварели отдельно от бананов - это одно (особенно учитывая что далеко не во всех магазинах есть сразу оба товара), но будете ли вы пробивать разными чеками макароны и хлеб, или тем более макароны разной формы? А ведь при подсчёте месячных трат именно на макароны, анализировать только "макаронные" чеки будет проще, чем выискивать подходящие товары из "общепродуктовых" чеков...

Проблема не в том, чтоб кислород для дыхания стал сжат вдвое сильнее, этим всё равно занимается наземный агрегат, а для перекачивания внутри ракеты, уже для дыхания, особой мощности и так не надо. Проблема в том, что теперь баки с дыхательным кислородом станут вдвое тяжелее, а ещё проектной толщины стенок может просто не хватить и придётся баки либо делать с ещё более толстыми стенками, либо ставить два бака рядом ( = существенное изменение конструкции). А ещё эти мешки с мясом туристы не только суммарно вдохнут вдвое больше, но и выдохнут вдвое больше, углекислый газ надо тоже куда-то девать.

А уж увеличение кабины в два раза - вообще смешно, это почти как в доме пытаться заменить лифт на вдвое более человекоподъёмный: мотор и трос ладно, а с кабиной-то что делать, пусть люди напихиваются вдвое плотнее? Тут надо всю шахту переделывать, а это перестройка части / всего здания... о чём и статья.

Или ещё лучше: ваша фирма производит фонарики, и вам пришёл заказ на 150 штук со следующими требованиями: питание от 3-х батареек AA, 1 лампочка накаливания, кнопку необходимо удерживать (не защёлкивается). "Отлично", думаете вы, "типичный набор компонентов".
Потом заказчик присылает письмо, в котором просит заменить лампочку на светодиод (в интернете вычитал, что они служат дольше и потребляют меньше энергии). Вы пожимаете плечами: "Ну ладно, конструкция почти та же самая, только вместо винтового патрона для лампочки - небольшая печатная плата со светодиодом."
Через 2 дня заказчик просит вас заменить батарейки на AAA, якобы для уменьшения веса. "Хм, придётся вставлять другой отсек для батареек, а отверстия от уменьшенных габаритов компенсировать дополнительными пластиковыми перегородками".
А затем заказчик просит вас поставить матрицу из 18 светодиодов, питание заменить на 3 батарейки типа D, а ещё добавить функции включения на половину и мигания красным. Как думаете, сколько компонентов у вас останется от предыдущей конструкции? Я думаю, что в лучшем случае кнопка

А как определить, сколько действий выполняет данный код, и самое главное - может ли количество действий в одном и том же коде различаться для разных задач/требований?

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

function print_quadratic_solutions(a, b, c) {
  const d = b * b - 4 * a * c;
  if (d < 0) {
    console.log("0 корней");
  } else if (d == 0) {
    console.log("1 корень", -b / (2 * a));
  } else {
    console.log("2 корня", -b - Math.sqrt(d) / (2 * a), -b + Math.sqrt(d) / (2 * a));
  }
}

Вроде логично разбить на 2 подфункции: решение и получение численных ответов, и печать, верно? А если следовать заветам Дядюшки Боба очень фанатично, то можно и до

такого дойти
function print_0_solutions() {
  console.log("0 корней");
}

function print_1_solution(x) {
  console.log("1 корень", x);
}

function print_2_solutions(x1, x2) {
  console.log("2 корня", x1, x2);
}

function print_solutions(x) {
  switch (x.length) {
    case 0: {
      print_0_solutions();
      break;
    }
    case 1: {
      print_1_solution(x[0]);
      break;
    }
    case 2: {
      print_2_solutions(x[0], x[1]);
      break
    }
  }
}

function get_number_of_solutions(d) {
  if (d < 0) {
    return 0;
  } else if (d == 0) {
    return 1;
  } else {
    return 2;
  }
}

function calculate_discriminant(a, b, c) {
  return b * b - 4 * a * c;
}

function solve_quadratic(a, b, c) {
  const d = calculate_discriminant(a, b, c);
  const n = get_number_of_solutions(d);
  switch (n) {
    case 0:
      return [];

    case 1:
      return [-b / (2 * a)];

    case 2:
      return [-b - Math.sqrt(d) / (2 * a), -b + Math.sqrt(d) / (2 * a)];

  }
}

function print_quadratic_solutions(a, b, c) {
  const solutions = solve_quadratic(a, b, c);
  print_solutions(solutions);
}

В 6 раз длиннее, зато каждая функция настолько мала, насколько возможно, ага.

А теперь представьте, что этот код размещён на HTML-странице, где есть поля ввода для a,b,c и кнопка для решения. Я бы вообще не стал делить этот код на функции, или даже отделять от получения значений из HTML-элементов, мне это кажется избыточным, я бы всё это поместил в единственный onсlick-обработчик.

И ведь никто не скажет как объективно лучше...

Information

Rating
3,602-nd
Registered
Activity