Как стать автором
Обновить

Я стал думать над мелочами в коде, и уничтожил все желание программмировать

Время на прочтение 24 мин
Количество просмотров 30K
Всего голосов 96: ↑54 и ↓42 +12
Комментарии 129

Комментарии 129

О, статья фила. Побежал за попкорном, пусть пока комментарии настаиваются

Фил, в расте нет наследования, а значит и нет всего класса описаннных тобой проблем.


Перепиши все на раст и вступай в ряды, пора!

Раст шикарен. Как и F#. Но у меня-то работа на сишарпе, куда тут денешься. Хотя нам завозят рекорды, и скоро будут DU, будет получше

Тебя дети читают, подумай, чему ты их учишь )))
Они вырастут и будут спорить какую иерархию классов сделать и как сообщать об эксепшенах в функции.


А должны были вырасти и спорить о том как решить любую задачу человечества через map/reduce

filter — частный случай reduce, не? Как и map.


Сортировку же можем, значит и медиану можем

filter, реализованный посредством reduce, не сможет корректно работать в некоторых не слишком надуманных частных случаях (функция, передаваемая reduce, должна уметь отличать ситуацию старта reduce, то есть, своего первого вызова от остальных вызовов, не всегда это тривиально, а иногда и вовсе невозможно), так что нет, не частный случай.
В P.S. я не спрашивал «можем или не можем», я спрашивал «как»

P.S. сообразил, как сделать, чтобы ситуации не надо было различать. Ну ладно, filter — частный случай reduce (но я всё же буду настаивать, что лучше его рассматривать, как самостоятельный инструмент)

P.P.S. Вот, кстати, пример, чем плох filter, реализованный через reduce: для корректной реализации потребуется создать копию исходного кортежа с добавленным пустым кортежем в начало. Это может быть совсем невозможно, если у нас настолько большой кортеж, что занимает большую часть памяти (у «чистого» filter такой проблемы нет, у него может быть проблема только с размещением результата, а тот может быть существенно компактнее)

P.P.P.S. Ну и вдогонку: почему бы тогда и про map не «забывать», если и она частный случай reduce?
Замечание к P.P.S.: если есть что-то, что может «на лету» выдавать нечто, удобоваримое для reduce, добавив пустой кортеж перед первым элементом, тогда filter может быть реализован через reduce без «неприятных побочных эффектов», описанных мной

Не выдержал, скажу все таки. Зачем нужно отличать первый элемент от остальных, не понимаю не только я, но и все авторы всех имплементаций filter во всех языках. (Вот, ниже в псевдокоде).


filter(enum, fun) = reduce(enum, new typeof(enum), fn e, acc ->
  if fun(e) then append(acc, e) else acc
end)
НЛО прилетело и опубликовало эту надпись здесь

Тогда уж


filter' : (fn : a -> Bool) -> List a -> List a
filter' f = foldr (\elt acc => if f elt then elt :: acc else acc) Nil

Вот теперь доказывайте :)

Эта штука будет работать, если кортеж состоит из кортежей, или запихнёт всё в копию первого элемента?

Я не понял вопрос, извините. Есть Foldable / Enumerable. Кортеж это, список, или массив — дело сто тридцать пятое.


Если на нем определен fold / reduce — то filter можно определить как показали выше (псевдоязык, haskell, idris соответственно).


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

В шарпе есть FFI и весь новый код после 1 января 2021 должен быть написан на расте в соответствии с сегодняшним Указом Путина «О сокращении выбросов парниковых газов».


How we integrate Rust with C#

Так найди работу на расте и все будет ровно так как ты хочешь.

Как_нарисовать_сову_найти_работу_на_расте.jpg

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Надо, да. К сожалению.

Подумайте над идеями, как это исправить «правильными» системами поиска по исходному коду. Которые завоюют мир, а вы, их автор, будете сами себе платить зарплату. Шутка. Я вижу (поверхностно, конечно) ваш психологический профиль, это не ваш метод. Ваш метод — сбросить пар на хабре, продолжить комфортно получать зарплату, где получаете. Я то же так делаю, но не сбрасываю пар на хабре.
И причина не в чистоте кода, а в том что когда у вас будет большой проект с несколькими языками, документацией и т.п. и кто-то решить поискать во всем объеме этой информации по имени класса Api он вас проклянёт, а по LicenseApi найденых вхождений будет на пару порядков меньше.

Мне кажется, или проблема вовсе не в нейминге, а в убогих средствах для поиска?

НЛО прилетело и опубликовало эту надпись здесь
Статья для дотнетчиков, так что, парни, давайте передохнём минуту и хорошенько поржём над «НАСТРОИТЬ ДЕБАГ».

Да, давайте поржем над Филом и пятью его загадочными сеньорами-фронтами, которые не смогли прочитать документацию электрона.
Когда все необходимые шаги прямо таки разжеваны в первых же ссылках гугла, и вообще сами по себе очень стандартные (запустить процесс с соответствующими дебаг-командами, подключить remote debugger) — тут конечно же без пяти сеньоров не обойтись.
Или у вас такая IDE, что не умеет в это всё, как умеет та же VSCode? Ну так проблема на вашей стороне, надо было брать инструменты, которые умеют.

Я нашел несколько рецептов для VS и WebStorm. Интересно, это пробовали и не подошло (ну мало ли какие там особенности). Или сеньоры специфические.


https://stackoverflow.com/questions/46500302/attach-visual-studio-debugger-to-electron-app
https://blog.jetbrains.com/webstorm/2016/05/getting-started-with-electron-in-webstorm/

Я однажды (поскольку с электроном меня жизнь не сильно-то сводила) для одного хорошего человека взялся подебажить — поставил электрон, скачал его код, дописал включение дебага, подцепился из VSCode, в котором я всегда пишу — всё завелось с полпинка.

Оно вот правда всё работает на уровне «прочти и сделай как написано», по крайней мере в VSCode. Вернее, работало еще в 2018.
Кстати, есть новая мода писать ',' в конце последней строки любого перечисления. Я её ненавижу, потому что, после запятой должно что-то идти.

MethodName(
parameter1,
parameter1,
parameter1,
parameter1,
parameter1,
)
Конкретно в параметрах метода так делать нельзя, в вашем примере будет ошибка компиляции.

Ну и сделано это для удобства использования при автогенерации кода, ненужны специальные подпрыгивания, чтобы отслеживать когда надо её ставить, а когда нет.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Многие из Java мира имеют альтернативное мнение и называют это
Checked exceptions — Java’s biggest mistake

Я тоже так думал в Java, пока не пописал год на C#. После этого изменил мнение на противоположное :)

У этой многострадальной запятой есть ещё одно назначение: при добавлении элемента в список мы не меняем предыдущую строку.
И легче смотреть историю изменений в git.

НЛО прилетело и опубликовало эту надпись здесь

Ага, работал с таким code style.


Но, в большинстве случаев — это вкусовщина, поэтому я не испытываю эмоций на сей счет.

НЛО прилетело и опубликовало эту надпись здесь
Что ты такое?(
SQL Management Studio стандартные запросы в таком виде генерирует:
/****** Script for SelectTopNRows command from SSMS  ******/
SELECT TOP (1000) [Id]
      ,[Field1]
      ,[Field2]
  FROM [DataBase1].[dbo].[Table1]

А если надо новый первый элемент вставить, то опять две строки менять.

Тогда пустой список аргументов/элементов придётся везде определять как
f(,
)
К сожалению, далеко не всем интересно изучать новые подходы и придумывать свои велосипеды. Они научились клепать как в гайде и отклонение от него — это нагрузка на мозги, к тому же нежелательная. Я вот, к примеру, недавно вычитал про такую штуку, как аспектно — ориентированное программирование. Вдохновился как круто можно будет в проекте все залогировать (пишешь код для логов в одном месте и все работает). Логов у нас великое множесто, подумал убедить всех внедрить… А потом подумал, что я услышу что-то вроде «ну хочешь — сделай», придется самому искать время на внедрение, а потом убедить всех коллег, что это круто. А потом придет товарищ и сделает как обычно, потому что он и не слушал, что я предлагал, и вообще ему бы быстрее задачу закрыть. И отбросил идею.
Вот так и выходит, что приходится равняться на стандарты тех, кто учиться не хочет и не хочет пробовать новые идеи.

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

Недавно была хорошая статья прямо не касающаяся конкретно программирования, но там есть очень правильная идея «рычага».

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

Я сильно надеюсь что в конце концов спецификации языка и IDE будут включать подобную поддержку из коробки, ну а пока каждый д… т как он хочет.
Нет оснований полагать, что макросы, генерация исходников или AOP значительно ускоряют разработку всегда и везде или хотя бы часто и в широком спектре задач. На поверхности все прекрасно, особенно с макросами. Все эти инструменты (а также ООП, ФП и т.д.) придуманы для решения проблемы сложности. Эти инструменты не адресуют проблему сложности напрямую, они дают «язык», на котором можно о проблеме говорить. И тут загвоздка — мы не знаем как понять насколько «язык» адекватен проблеме, кажется мы даже не знаем как понятие «адекватен проблеме» определить.

Мы даже не знаем проблему определить, кроме как "софт — это сложно"

Я регулярно думаю о частной проблеме — человеческий, но формализованный язык для общения с самим собой (ладно с ним, с остальным человечеством). Переносимость идей, алгоритмов через моды / синтакс разных ЯП / изменения в синтаксе даже одного ЯП (мой ЯП — C++, он стал динамичнее меняться в последние лет 15). Идеи AOP, DSL мне лично нравятся и для меня лично они адекватны проблеме. Далее, я — довольно типичный «опытный программист со стажем», адекватность для меня что-то значит и для остального человечества. Это я просто в антитезу вашему (понятному мне) скепсису.
НЛО прилетело и опубликовало эту надпись здесь

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


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


Некоторым даже за это платят, всякие Technology Advocate.

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

НЛО прилетело и опубликовало эту надпись здесь
Недавно тоже захотел использовать AOP и подтянуть какой-то weaver. Так вот, проблема с либами таки, их живых — fody да postsharp. При чем у первого половина плагинов мертвы автор пропагандирует какую-то странную идеологию «добровольно принудительной оплаты», хотя лицензия MIT, а второй дороговато стоит (комюнити вресия уровня «ну вот это у тебя проработает только неделю после билда» SIC). В итоге таки остановился на фоди, но юзаю пока по миниммуму, только для нулчеков. Потом посмотрим, есть идеи.

TL;DR: я выстрадал и выкатил 100500 новых правильных практик написания кода: нейминга, форматирования, наследования, инкапсуляции и прочего, но мой код можно понять только изнутри той IDE, которая нравится мне.

Всё так. Только в .net все пишут или в райдере, или в студии с решарпером, который превращает её в райдер. Короче, ide то у всех одна и та же.

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


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


Так что я все-таки убежден, что код обязан не терять в читаемости безо всяких там IDE.

Я бы подискутировал, на самом деле. Хороший код всегда красивый, красивый код не всегда хороший. Но эти вещи связаны. Эстетическая красота кода — это в том числе и красота архитектуры и дизайна — качества именно хорошего кода.


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

Хороший код всегда красивый, красивый код не всегда хороший.

Отнюдь. Иногда «годный» код от «хорошего» — отличают бенчмарки, и приходится драться за каждую миллисекунду. И вот тут-то красотой приходится жертвовать. Пример из совсем недавнего: писал я там одну библиотеку, и очень красиво хранил внутреннее состояние в AVL Tree. А потом невзначай выяснилось, что удалений в моем случае практически нет, добавления обычно можно свести к конкатенации, а вот поиск прям частый. И я переписал все на связных списках с костылями, дискретным доступом по типу хэшмапа (O(1)) и кодогенерацией matching clauses для частых паттернов. И выиграл в производительности в 10 раз.


Стал ли код менее красивым? — Несомненно. И понять его теперь в двадцать раз сложнее.


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

Возможно. Но я не готов запоминать какой цвет в каком языке какому чему соответствует. В нескольких языках из моего активного словарного запаса понятия «интерфейс» вообще нет (elixir). В других — он означает совсем не то же самое, что в шарпе и джаве (idris).




Или вот исключения и ивенты. Что такое ивент? А в языке с нативной моделью акторов? А в джаваскрипте? А в руби? Синий или зеленый? Курсив или болд? А так-то, для общего понимания кода, мне это все не важно: детали реализации. Мне важно, что автор этого кода считает сие ивентом, что я пойму по ключевому слову Event, а по раскраске не пойму. И если в коде throw new NotifyEvent();, то тут что-то не так, а если throw new Notification(), и Notification красненькое и жирненькое — то я хз.


В общем, с тезисом про то, что код должен доставлять эстетическое наслаждение — я согласен чуть более, чем полностью (с оговорками, конечно, но в общем случае — так). А с тем, что без IDE мне потребуется на понимание в пять раз больше времени, и это нормально — категорически нет.

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

Есть такая концепция как intelligence amplification — в самом простом случае можно сравнить эффективность решения математических задач в уме vs человеком у которого есть листок бумаги и ручка. Вполне допускаю что существуют те кто в уме будут более эффективно решать, но в целом бумага плюс ручка дают существенную фору.

Также и IDE, правильная IDE является очень эффективным усилителем как качества так и производительности _обычного_ программиста. Даже плагины к ней могут играть существенную роль (VisualStudio vs VisualStudio+ReSharper).

Ээээ… Спасибо на добром слове.


эффективность решения математических задач в уме vs человеком у которого есть листок бумаги и ручка

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


Код же читают больше и лучше, чем пишут, так вроде кто-то из великих демагогов сказал?


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


И вот тут-то и окажется, что документация должна быть first class citizen, а интерфейсу хорошо бы прямо с порога заявить о своей принадлежности племени интерфейсов.


Простой пример: хаскель вон типизирован не в пример лучше шарпа, что как бы должно помогать в IDE найти нужную функцию прям по сигнатуре. Но читать хаскель невозможно, если ты не пишешь на нем 24/7 — из-за дикой мешанины бесконечного количества функций в Prelude и стандартных импортах. Тут так же: вся красота, описанная в статье — write-only. Читателю будет легче, если у интерфейса будет префикс. Точка.

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

И вот тут-то и окажется, что документация должна быть first class citizen
В теории да, но на как говорят
В теории, разницы между теорией и практикой не должно быть. Но на практике ...
Есть объектвиная реальность данная нам в ощущения и документация там «illegal immigrant» по вашей терминологии.
Читателю будет легче, если у интерфейса будет префикс. Точка.
Моя точка зрения, что надо следовать принятым практикам, чтобы завтра пришёл новый боец и с достаточной вероятностью он уже знает что, как и где. Для c# это значит префикс «I» перед интерфейсом и префикс «T» перед дженериками. Даже если лично моё чувство прекрасного страдает.

Если же в хаскеле не принято ставить префиксы (не знаю так это или нет), то лучше не надо, даже если сильно хочется.
НЛО прилетело и опубликовало эту надпись здесь
Стиль, с которым я согласен больше всего (но ленюсь следовать)
А IDE (если вы пользуетесь idea + intellij-haskell) не позволяет заставлять вас следовать определённому стилю или по крайней мере помогать в приведении к выбранному формату.
НЛО прилетело и опубликовало эту надпись здесь
неудобство человека который раз в полгода что-то посмотрит, с учётом того что он и так язык не знает и ему придётся детально разбираться, может не стоить выгод приобретаемой основной командой

  • человека → всех людей, которые заглянут в код
  • и так язык не знает → не использует язык в режиме 24/7, знать язык он может лучше автора
  • детально разбираться → ровно наоборот, понять структурно и архитектурно
  • выгод приобретаемой основной командой → в случае, если в команду не приходят новые люди, все в команде считают это выгодами и вообще — если эта выгода есть.

документация там «illegal immigrant»

Зависит от культуры, сложившейся в сообществе. У нас в уютном мирке эликсира принято соотношение документация ÷ код ≥ 1.0. Потому что сигнатуры часто недостаточно, чтобы рассказать, как эта функция работает. По сигнатуре не понятно, что, например, случится, если виртуальная машина грохнет этот гринтред из-за переполнения стека его вызовов из других гринтредов.


Для однопоточного перекладывания джейсона это, наверное, оверхед, впрочем.


надо следовать принятым практикам

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


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

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

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

НЛО прилетело и опубликовало эту надпись здесь
Я тут последние полгода-год пользуюсь idea + intellij-haskell, и оно прям рулит и педалит с точки зрения навигации по коду, включая прыжки в библиотеки.

Вы, блин, с каких пор стали дискутировать с тремя случайными словами, вырванными из контекста? Я, вроде, не на эликсире же написал, а на чистом русском, которым вы прям неплохо владеете: писать хаскель легко, спасибо типам и IDE.


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


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


почему в идрисе или агде нет какого-нибудь хуглоподобного поиска

Потому что не хватает рук? Я близок к тому, чтобы самому этим заняться, как только второй компилятор хоть чуточку стабилизируется и превратится в полноценный LS, как первый — нырну.

Да, согласен. Моё утверждение, что хороший код всегда красивый — неверное. Читабельный и поддерживаемый код всегда красивый. А в случае с перфомансом — часто есть трейдоф между читабельностью и производительностью, и если код критичен к скорости, то он может быть не красивым и при этом хорошим.


Другой вопрос, что критичность по перфомансу — редкость. а вот читать и поддерживать надо всё.

Одно из самых красивых решений — код для быстрого вычисления обратного квадратного корня. Это, наверное, самый легендарный хак из всех.
Но код «красивым» назвать язык не повернется. Это сплошной WTF.
Впрочем, времена хакеров ушли, пришли времена нытиков.
Разобрались с префиксами, теперь нам режут глаза фигурные скобки.

Ага, щаз! Я встречал вот такой гибрид:


internal static class SomeClass {

    public static void DoSomething(bool arg1, bool arg2) {

        if (arg1) {

            if (arg2) {

                some_precious_code ...;
                some_precious_code ...;
                some_precious_code ...;
                some_precious_code ...;
            }
            else {

                some_more_precious_code ...;
                some_more_precious_code ...;
                some_more_precious_code ...;
                some_more_precious_code ...;
            }
        }
        else {

            some_more_precious_code ...;
            some_more_precious_code ...;
            some_more_precious_code ...;
            some_more_precious_code ...;
        }
    }
}

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

Тех, кто экономит пробелы, нужно приговорить к пожизненному расстрелу!


Почему закрывающая скобка стоит не в том же столбце, что и открывающая? Это ж как потом читать что тут где во что вложено?!

Это ж как потом читать что тут где во что вложено?!

Отступы же, которые делаются согласно кодстайлу.

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


В таком виде как-то ни туда, ни сюда…

Эти "нравится" и "не нравится" — вопрос привычке. Вон в Джаве так все пишут.

Согласен. Я и не такое вижу периодически, но моих страданий от этого прибавляется, а потому сам обычно переношу открывающую скобку на новую строку. В отличие от автора поста я воспринимаю это так:
<Заголовок> Mega_function </Заголовок>
{ </отступ от заголовка>
<Полезный код>
a=a+b
</Полезный код>
} </Отступ перед новым "параграфом" кода>


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

Ну вообще, я ниже написал, что мой выбор, чтобы все писали по стайл гайду принятом в данной экосистеме. Если C# — то скобки на отдельной строке. И желательно проверять все стайлкопом.


А в другой экосистеме я буду по другому. Вот в питоне и F# вообще только отступы.

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

У каждого блока кода получается как бы «смысловой заголовок» с выступом влево и небольшой отступ перед следующим блоком, что визуально его оформляет в отдельную сущность. В том же варианте, который Вы показали, if'ы, объявления и их содержимое(!) мною при беглом чтении воспринимаются как отдельные «смысловые блоки», что несколько затрудняет и замедляет работу.

Кстати, специально для таких обсуждений у меня есть такой вариант стиля. И скобки на одних столбцах, и нет лишних вертикальных пробелов. Лепота!
public static void DoSomething(bool arg1, bool arg2)
{   if (arg1)
    {   if (arg2)
        {   some_precious_code ...;
            some_precious_code ...;
            some_precious_code ...;
            some_precious_code ...;
        }
        else
        {   some_more_precious_code ...;
            some_more_precious_code ...;
            some_more_precious_code ...;
            some_more_precious_code ...;
        }
    }
    else
    {   some_more_precious_code ...;
        some_more_precious_code ...;
        some_more_precious_code ...;
        some_more_precious_code ...;
    }
}

В том же варианте, который Вы показали, if'ы, объявления и их содержимое(!) мною при беглом чтении воспринимаются как отдельные «смысловые блоки», что несколько затрудняет и замедляет работу.

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


Также у нас ещё есть закрывающие скобки. И вот они все стоят каждая на отдельной строке. И это не всегда приятно.

В основном согласен, но не с этим
Кстати, есть новая мода писать ',' в конце последней строки любого перечисления. Я её ненавижу, потому что, после запятой должно что-то идти

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

А чем не угодила запятая в конце списка?
Это в русском языке после запятой должно что-то быть, а в данном случае это способ "перебздеть", чтоб однозначно было понятно, что имя параметра/переменной/значение элемента массива указано верно и окончательно. Я бы, конечно, какой-нибудь октоторп использовал вместо запятой, но создатели языков программирования решили иначе, а потому имеем что имеем…

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

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

Код, который он при этом производил — был, в общем-то абсолютно никакущий. По любым стандартам, даже самым мягким. Там были баги. Там было множество неотработанных edge case. Естественно, там не было Идеологически Верного Нейминга и Форматирования. Тесты там существовали в виде экспериментальных прогонов этого кода в main(). После него, на этот код надо было напустить еще парочку более тупых программистов (типа меня, в те времена я еще немного в Яву мог), которые бы пришли, навели порядок, пофиксили баги, написали бы правильные имена, тесты, и всё вот это. Разница, однако, была в том, что он за четыре дня писал в целом рабочий код, который мы написать за хоть сколько-нибудь обозримое время просто не могли (за бесконечное время конечно бы написали бы, но у бизнеса столько нет) — и этот код приносил неслабые деньги, его, после прилизывания, можно было допиливать до MVP и показывать серьезным дядькам в галстуках и продавать еще не написанные продукты с его использованием за огромные деньги.

Так вот, полезность такого «говнокода» (в кавычках) я не просто мог видеть, но и собственными глазами видел, в форме циферок в долларах с большим количеством нулей справа, отображающихся в публичной финотчётности конторы, спустя квартал после того, как мы это всё облизали и собрали демки.
А вот полезность идеологически вылизанного перекладывателя жсона (или http-запросов, что совсем недалеко ушло) — она мне представляется прямо таки на порядки более сомнительной. Соответственно, оформительские многочасовые страдания над таким кодом — они недалеко ушли от многочасовых оформительских страданий над кодом местячкового локального пет-проекта для конкретной узкой задачи, который заведомо никому не нужен и вообще пишется write once кодом.

Прикольное, но на практике совершенно бесполезное извращение.
Ну все-таки прототип и каркас это разные вещи. Прототип пилится чтобы быстро понять, возможно ли оно в принципе. Автор же скорее говорит про каркас будущей системы, в которой вроде как уже прототипировать не надо, а надо сделать так, чтобы было красиво -> понятно. Хотя и рассмотрено это на небольшой задаче, поэтому и кажется что тут и заморачиваться незачем
Это вообще сугубо неважный вопрос. Важный — зачем оно всё надо, и для чего будет использоваться. И какие деньги принесет.
Если вам надо переложить пять хттп-запросов — многочасовые страдания над каркасом идеального перекладывателя запросов бесполезны.

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


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

И единственный способ это сделать — отнаследоваться от класса и прокинуть его в паблик

В народе этот антипаттерн известен как "Паблик Морозов" :)

Кстати, есть новая мода писать ',' в конце последней строки любого перечисления.

Зато когда нужно добавить новый элемент, в диффе изменений у вас будет не 1 строка изменена (добавлена запятая) и 1 строка добавлена, а просто 1 новая строка. Это позволит избавиться от лишних конфликтов в этой строке при мерже с мастера в ветку фичи, да и просто, блейм гита будет более правильным.

Ощущение, что автор статьи не работает в команде.
Да и в целом — код без комментов и «лишних» скобок? Поддержкой видимо тоже не занимается.
НЛО прилетело и опубликовало эту надпись здесь

Я слышал, что у них есть общепринятый инструмент для стат типизации, нет?

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

НЛО прилетело и опубликовало эту надпись здесь
Да, есть тайпчекер, mypy. Норм, но похуже тайпскрипта.
НЛО прилетело и опубликовало эту надпись здесь
Поддерживаю — Python, Django+++++++

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


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


Префиксы и суффиксы теоретически зло, но я буду писать как принято в данной экосистеме, чтобы быть понятным. Ибо зло это небольшое. Суффикс Exception тоже нехорош, так как по названию класса должно быть понятно, что это ошибка (Например InvalidArgument).


Они и должны называться одинаково, это одинаковые по смыслу сущности

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


Название API кажется странным. Для внешнего потребителя все API. Например строка по такой логике тоже должна называться API. String.API.


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

В целом это и есть посыл статьи. Я вижу вещь, которая как принято, она мне не нравится, я начинаю думать — как лучше. И в итоге-то все равно говно какое-то.


Название API — и правда странное, моя ошибка. Должно быть — WebApi, или %Domain%WebApi

тогда мне непонятно, почему это интерфейс, а не неймспейс, и как он может быть у Http клиента менеджер лицензий или это не HttpClient а RestClient? Тогда слово Web должно быть уже внутри слова HTTP.


Скорее всего пользователь сначала определяется какой конкретный API использует, а потом уже оперирует сущностями.


using KingOfDevs.SpecificRest.WebApi;

// если по-вашему а не по стандарту
License.Repository licenses = GetSpecificRestClient().Licenses;

licenses.Remove(myLicense);

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

Можно тоже в холиваре поучаствую? :)


Лично я люблю префиксы для полей классов, потому что они


  • Помогают автодополнению — я пишу m_ и сразу же получаю весь список полей; обычно дополнение ориентируется на первую букву, которую я не всегда помню точно.
  • Они помогают избегать дурацких проблем с придумыванием имен для параметров в конструкторах или геттерах.

Но вообще, как пишущий на С++, скажу одно — иметь единое соглашение об именах для всего языка (как в C#, например) — это великолепно, вы просто не понимаете своего счастья! Пусть лучше будет неидеально, но зато единообразно.

НЛО прилетело и опубликовало эту надпись здесь
Гипотеза: дело в том, что первые пользователи C++ были C программисты, экономили байты исходного кода (кроме того, замечательная более поздняя идея делать this. (this-> на C++, мне лично сама -> противна из-за nullptr dereferencing) была придумана более поздно, в языке Java. Так сложилось, короче. C++ более старый, логичнее задуматься о том, почему и чем идея с this. (Java, C#), увеличивающая многословность, количество ударов пальцами по клавиатуре, правильная и полезная. Я не подвергаю эту идею сомнению, хорошая идея, но не универсальная. Есть другие идеи, точки зрения, инструменты проверки соответствия кода оным.
НЛО прилетело и опубликовало эту надпись здесь

Мне this нравится тем, что во всяких парных методах (compare, equals, etc.) можно называть аргумент that и обращаться к полям как this.field, that.field.

Я пробовал так делать — и это просто дольше, длиннее и менее удобно. Особенно -> ставить (даже если IDE автозаменяет точку на стрелку, она при этом немножко подтупливает).


Это, разумеется, мои личные ощущения — но и весь пост о личных ощущениях. Почему в целом по языку не принято — судить не берусь, но в С++ вообще туго с единым стилем; может где-то и принято.

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

Есть же линтеры всякие. В случае с шарпом .editorconfig имеет правило для того чтобы подставлять this или подчёрк где нужно и может сломать билд при надобности.
  • Они помогают избегать дурацких проблем с придумыванием имен для параметров в конструкторах или геттерах.

Проблемы языка, не? В других подобных проблем просто нет:


struct Dto {
    id: u32,
    name: String,
}

impl Dto {
    fn new(id: u32, name: String) -> Self {
        Self { id, name }
    }
    fn name(&self) -> &str {
        &self.name
    }
}

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

Я бы не сказал, что этот пример демонстрирует преимущества раста в экономии на именах переменных. В этом примере как раз показывается, что Rust вначале создаёт сам себе проблему с boilerplate code (тк требует в конструкторе в общем случае указывать имена полей), отсутствующую в C и плюсах:


impl Dto {
    fn new(_id: u32, _name: String) -> Self {
        Self { id: _id, name: _name }
    }
}

И потом героически её решает с использованием сахара под названием field init shorthand, который и применяется в вашем куске кода. 1 — 1 = 0.


Сишный код не требует никаких имён полей:


typedef struct Dto {
    unsigned int id;
    const char   *name;
} Dto;

const Dto make_dto(unsigned int id, const char *name)
{
    Dto ret = {1, "abc"};
    return ret;
}

Если уж демонстрировать безымянные конструкции раста, то на tuple struct:


struct Dto(u32, String);

fn main() {
    let foo = Dto(1, "abc".to_string());
    println!("{}", foo.1);
}

В C/C++ подобный способ инициализации (кстати, как он называется) чреват отстрелом ног — порядок можно перепутать, если типы позволяют:


typedef struct Dto {
    int foo;
    int bar;
}
const Dto make_dto(int bar, int foo)
{
    Dto ret = {bar, foo};
    return ret;
}

Либо есть designated initializers (C99, C++20):


{.foo=123, .bar=456}

которые возвращают проблему дублирования, о которой вы говорите. Так что, ИМХО, в Rust сделано неплохо.

Такой способ инициализации возможен и в расте, только еще имена полей надо указывать, порядок на них не задан. Но это работает только до тех пор, пока ваш тип — это DTO, иначе приходится делать поля приватными и вводить конструкторы. И ваш пример какой-то странный, в make_dto аргументы не используются.
Удивительно, как много созидательной энергии, увы, тратится на форматирование, соглашения о наименованиях, такие мелкие штуки, которые Компьютер должен делать (и делает) проще для мыслителей-программистов. Однако, у мыслителей-программистов есть некоторая проблема с приоретизацией, реальная проблема — человеческий мозг хватается за мелкие штуки первым делом, ему проще выполнить рутинную работу по переформатированию, переименованию, расставлению скобочек и запятых красивенько так — и это на подсознательном уровне. При том, что Компьютер сделает всё это ОК за миллисекунды.

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

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

Пример реализации: автор(ы) языка Nim забил(и) (в основном) на различия CamelCase snake_case nocase bAdCaSe в наименованиях. Хороший пример послать паразитную проблему подальше, не идеальный (в идеале в проекте есть спеллчекер в идентификаторах и правильная конверсия в CamelCase, snake_case, nocase по настройкам индивидуального разработчика — плюс строгое выпалывание bAdCaSe, конечно).

Слабое место — поиск, но это технически решаемая проблема. Интересный комментарий выше — про полезность минимального Hungarian вроде "_" или «m_» префиксов, теперь уже из-за удобств IDE. С чего я начну новую строку моего идеального кода? Первый элемент намеренья обозначен довольно рудиментарным префиксом, а там уже — любимая мозгом рутинка, как в компьютерную игрушку играешь. Все довольны (главное, мозг :) ).
Я не пишу на .net, разрабатываю проекты на php, но каждый раз задумываюсь над этими и другими сотнями мелочей. При этом каждый новый проект ты начинаешь с идеей «Напишу проект лучше и круче по архитектуре, чем прошлый», а спустя 3 часа ловишь себя за копированием каких-то классов из старого проекта в новый. Да, ты закладываешь структуру нового проекта чуть лучше, но в ходе работы над проектом всплывают другие косяки, которые ты уже закрывал в старых проектах, но в этом не можешь, так как заложил все «круче» и «лучше». И вот ты снова пишешь неидеальный проект, круг замкнулся.

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


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

Мне важно насколько много кода ты увидишь в одном экране. В этом плане я настоящий идеалист — если файл с кодом требует больше одного моего экрана (он у меня довольно мелкий), я делаю всё что могу, что бы его сократить.

Одна из причин, почему я не смог пользоваться райдером — это остутствие функции/экстеншена Shrink Empti Lines https://marketplace.visualstudio.com/items?itemName=VisualStudioPlatformTeam.SyntacticLineCompression
Абсолютный мастхэв, без которого использование места на экране кажется варварством.

Со многим согласен, хотя пишу на PHP. Любимый стайлгайд — Doctrine. В нём, например запрещены суффиксы/префиксы interface/exception/abbstract. Почти не могу представить ситуацию, когда они важны, кроме интерфейса или абстрактного класса с единственной реализацией.

но я за постфикс `Exception`

Чуть менее чем все использования SomeThingException помещаются в два кейса:
catch(SomeThingException ex)

и
throw new SomeThingException()


То есть по окружению легко понять, что ты имеешь дело с эксепшенами, фтопку постфиксы ;-)

Кстати ведь да

outcome switch
{
  { NotFound: { code : 404 } } => ...,
  { NotAllowed: { role : "Admin" } => ...,
};

Чё-как, кто тут эксепшон?

У вас тут Ok и Err/Right и Left не хватает

А есть разница, кто из них эксепшон?
Обычно это будет в контексте например catch блока или как то ещё. Очень редкий кейс, когда исключение ходит по коду не через throw\catch.

logger.exception(E) или tracer.exception() — самые частые из этих редких :)

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

Пха. «Король разработки». Неужели я таким же был, кхм… «Королём»…
А тут проблемы с платформой — в C# с моками всё очень плохо — если захочешь делать мок не на интерфейс, а на класс с не виртуальными свойствами и методами — пойдешь в жопу.

Это не проблемы, это хорошо. Я видел код на Python (в котором можно мокать почти всё), в котором для тест кейсов описывали штук пять-десять декораторов unittest.mock.patch (которые подменяют класс/метод на мок-объект), в том числе, мокающие некоторые приватные функции модуля при тестировнии его самого. Я вообще не уверен, что такой тест способен что-то отловить. Особенно, если учесть, что у питона динамическая типизация и даже изменение сигнатур зависимостей мы не заметим (они же замоканы!). mypy есть, но помогает не всегда.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Узбагойся и читай «Чистый код» перед сном.
Моя война с большими файлами продолжается — я строго против xml-документации. Она всегда уродует код, иногда делает понятнее хреновый код, иногда дублирует информацию, представленную хорошим кодом. Братан, у тебя есть имя неймспейса, имя класа, имя метода. Имена параметров. Их типы, и имена этих типов. Если всех этих вещей тебе мало, что бы объяснить, как мне использовать твой код, документация тебе не поможет. Она просто замаскирует твою некомпетентность.

Желаю автору почитать MSDN без текстов, с одними лишь именами функций и параметров.

Что в программировании важнее всего?


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


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


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


Метафизически, существует только одна реальность — та, которую мы воспринимаем. Структуры данных — это концепции, основанные на правильном, непротиворечивом, логическом восприятии реальности.


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


Нет, это относится не только к средневековым монахам. Таким образом я вижу эту статью.


Вам может стать плохо от того, какую громадную неразборчивую систему возвёл автор. Автор упоминает: последние версии ПО, экспериментальные фичи, выбор IDE, как назвать интерфейс, как избежать длинных названий, принятые конвенции по именованию, обвинение конвенций, другие сервисы по работе с кодом (гитхаб), проблемы моков, сравнение C# с F#, оформление скобок, посторонняя мысль о красоте кода, посторонняя мысль о тайпскрипте и фронтенде, зрительное восприятие кода, заметка о привычках, размышление об абстракциях, xml-документация, многострочный код, префиксы, мода на запятые…


Предложения, под-предложения, под-под-предложения, упоминание всего что только придёт в голову, ссылки на реальные знания о программировании, на псевдо-знания, выбрасываемые в случайном порядке, основанные на единственном строительном элементе: отсутствие определений. Это интеллектуальный яд, который парализует мышление.


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


Если вы хоть раз задавались вопросом: «Почему я не получаю удовольствия от программирования?» — обратите внимание на ту статью. Мозг, оторванный от реальности, не способен испытывать удовольствие.


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


Для того, чтобы уметь отражать эти атаки, нужно быть первоклассным философом. Подобно тому как программист может стереть плохую программу, первоклассный философ может стереть миллионы бессмысленных слов. Моя статья не является руководством о том как таким стать. Для этой цели я могу порекомендовать книгу “Introduction to Objectivist Epistemology.”


Здесь коротко написано о чём эта книга: https://aynrand.org/novels/introduction-to-objectivist-epistemology/


Эта книга помогла мне вернуть фокус в области программирования с нео-мистиков из примера выше к реальности. Надеюсь она поможет и вам.


“Человек ни непогрешимый, ни всезнающий; если бы он был таковым, такая дисциплина как эпистемология... не была бы ни необходимой, ни возможной:... Человек является существом волевого сознания; за гранью уровня восприятий – уровня неподходящего познавательным требованиям для его выживания – человек должен получить знание своими собственными усилиями, которые он может выполнять или нет, и процессом разума, который он может применять правильно или неправильно. Природа не даёт ему автоматической гарантии его ментальной способности; он способен на ошибки, упущения, психологическое искажение. Ему нужен метод познания, который он сам должен открыть: он должен открыть как использовать его рациональную способность, как подтвердить свои выводы, как отделить истину от лжи, как установить критерий что он может принять за знание.”
Зарегистрируйтесь на Хабре , чтобы оставить комментарий