Начинающий программист совершенно уверен в том, как все должно быть, но не знает как и шагу ступить в конкретной ситуации. А опытный программист не уверен в том, как все на самом деле, но точно знает, как действовать в конкретной ситуации.
Концепции, парадигмы, паттерны и принципы, построены как мифы и верования. И самое парадоксальное в мифе, что он работает, дает хорошие результаты в ежедневной практике. Не нужно думать о нем, как о чем-то мистическом, выдуманном, отвлеченном. Если программист избавится от мифологического сознания, например перестанет верить в микросервисы, в nodejsоднопоточный, в скалярные типы данных, перестанет писать на примесях и мидлварах, то картина мира рассыпается и он не может ничего написать. Чтобы опять начать что-то создавать, нужно построить другой миф. Только ощущение, что у тебя сложилась картина мира, позволяет перейти от теории к практике. Но любая картина мира состоит из разрозненных фактов, которые переклеены мифом, иначе, бы мы утонули в зазорах между знаниями, как в пустотах между электронами и атомами. Без мифа мир страшен, непредсказуем и неуправляем. Опытный программист просто имеет несколько мифов в голове и может между ними переходить, некоторые могут даже конструировать свои, и такое конструирование может быть только интуитивное, если его начать логически строить, то никто не поверит. В мифе должны быть нестыковки, странности, даже противоречия, вот это заходит в голову идеально. Это инструмент, который позволяет действовать эффективно, скрывать сложность, давать целостную картину мира, но не слишком идеальную, чтобы было место для развития.
Концепции, парадигмы, паттерны и принципы, построены как мифы и верования. И самое парадоксальное в мифе, что он работает, дает хорошие результаты в ежедневной практике. Не нужно думать о нем, как о чем-то мистическом, выдуманном, отвлеченном. Если программист избавится от мифологического сознания, например перестанет верить в микросервисы, в nodejsоднопоточный, в скалярные типы данных, перестанет писать на примесях и мидлварах, то картина мира рассыпается и он не может ничего написать. Чтобы опять начать что-то создавать, нужно построить другой миф. Только ощущение, что у тебя сложилась картина мира, позволяет перейти от теории к практике. Но любая картина мира состоит из разрозненных фактов, которые переклеены мифом, иначе, бы мы утонули в зазорах между знаниями, как в пустотах между электронами и атомами. Без мифа мир страшен, непредсказуем и неуправляем. Опытный программист просто имеет несколько мифов в голове и может между ними переходить, некоторые могут даже конструировать свои, и такое конструирование может быть только интуитивное, если его начать логически строить, то никто не поверит. В мифе должны быть нестыковки, странности, даже противоречия, вот это заходит в голову идеально. Это инструмент, который позволяет действовать эффективно, скрывать сложность, давать целостную картину мира, но не слишком идеальную, чтобы было место для развития.
⭐️ Good and bad cases for TypeScript union types based on JavaScript V8 optimizations
👍 Good cases for union types:
- Union of strings instead of enum:
- Union of numeric as status or result code: type
- Union with shared properties:
- Union with common method:
👎 Bad cases for union types:
- Polymorphic object shapes causing depots:
- Requiring extensive "if"-logic and type checking:
- Inconsistent return types:
- Mixed primitives and objects:
- Сontradictory members:
- Union types that include any:
- Incompatible contracts:
🎁 Empty value for primitive types and reference types:
- Use
- Use
- Avoid mixing symbols with other types in unions
👍 Good cases for union types:
- Union of strings instead of enum:
type Direction = 'north' | 'south' | 'east' | 'west';
- Union of numeric as status or result code: type
StatusCode = 200 | 201 | 204 | 400 | 500;
- Union with shared properties:
type MailTarget = User | Company;
(both with email
)- Union with common method:
type Thenable = Promise | Query;
(both with then
method)👎 Bad cases for union types:
- Polymorphic object shapes causing depots:
type Something = User | Socket | string;
- Requiring extensive "if"-logic and type checking:
type Input = string | number | boolean;
- Inconsistent return types:
function getData(id: number): string | string[];
- Mixed primitives and objects:
type Value = number | { value: number };
- Сontradictory members:
type Person = { name: string; } | { name: number[] };
- Union types that include any:
type FlexibleType = number | any;
- Incompatible contracts:
type Handler = (() => string) | ((event: Event, data: any) => void);
🎁 Empty value for primitive types and reference types:
- Use
null
for empty reference types: Object, Function, Array
, etc...- Use
undefined
for empty primitive types: string, number, boolean, bigint
- Avoid mixing symbols with other types in unions
💡 Способы создания более сложных абстракций из простых в ООП и функциональном программировании сильно пересекаются:
∙ Наследование - для ООП кажется, что все понятно, но применять наследование нужно не для расширения абстракции, а для сужения, что в ФП достигается типами, а для построения более сложных абстракций из более простых в ФП используют композицию, замыкания, функции высшего порядка (обертки, декораторы).
∙ Композиция - в ФП композиция везде, а вот в ООП обычно недооценена, реализуется через создание экземпляра одного класса внутри конструктора другого, композиция создает меньше зацепления и зависимости, проще тестировать, когнитивная нагрузка меньше.
∙ Агрегация - похожа на композицию, но ответственность за инстанцирование не на классе-владельце, т.е. создание экземпляров, вынесено в другие абстракции, а агрегирующий класс получает их уже готовые, чаще всего через конструктор и объединяет.
∙ Миксины - примешивать к готовым экземплярам ссылки на другие, это хаос, в ФП такого нет, и три предыдущие способа гораздо предпочтительнее, но если нет никакого более красивого выхода, то можно применить, как временное решение, создающее техдолг.
∙ Ассоциация - иногда под этим термином понимают взаимодействие абстракций, это нормально, но иногда это значит внешнюю агрегацию, в худшем случае - через миксин, в лучшем - через сеттер, так что, это тоже создает зацепление и технический долг.
∙ Делегирование - это подвид композиции, когда интерфейс внутренней абстракции полностью реализуется наружной, по сути это прямая замена наследования, без использования наследования и проблем, связанных с ним.
∙ Наследование - для ООП кажется, что все понятно, но применять наследование нужно не для расширения абстракции, а для сужения, что в ФП достигается типами, а для построения более сложных абстракций из более простых в ФП используют композицию, замыкания, функции высшего порядка (обертки, декораторы).
∙ Композиция - в ФП композиция везде, а вот в ООП обычно недооценена, реализуется через создание экземпляра одного класса внутри конструктора другого, композиция создает меньше зацепления и зависимости, проще тестировать, когнитивная нагрузка меньше.
∙ Агрегация - похожа на композицию, но ответственность за инстанцирование не на классе-владельце, т.е. создание экземпляров, вынесено в другие абстракции, а агрегирующий класс получает их уже готовые, чаще всего через конструктор и объединяет.
∙ Миксины - примешивать к готовым экземплярам ссылки на другие, это хаос, в ФП такого нет, и три предыдущие способа гораздо предпочтительнее, но если нет никакого более красивого выхода, то можно применить, как временное решение, создающее техдолг.
∙ Ассоциация - иногда под этим термином понимают взаимодействие абстракций, это нормально, но иногда это значит внешнюю агрегацию, в худшем случае - через миксин, в лучшем - через сеттер, так что, это тоже создает зацепление и технический долг.
∙ Делегирование - это подвид композиции, когда интерфейс внутренней абстракции полностью реализуется наружной, по сути это прямая замена наследования, без использования наследования и проблем, связанных с ним.
List<List<T>>
Please open Telegram to view this post
VIEW IN TELEGRAM
— Почему вы не избавляетесь от сложности и технического долга?
— Вы что, мы столько сил потратили на этот крутой код, он нам очень дорог!
— Вы что, мы столько сил потратили на этот крутой код, он нам очень дорог!
🧩 Можете ли вы предложить пример кода для иллюстрации принципов? (если спросят коллеки на собеседовании)
Anonymous Poll
47%
Композиция классов
31%
Агрегация классов
27%
Делегирование
61%
Единственная ответственность
50%
Принцип открытости/закрытости
46%
Принцип подстановки Лисков
47%
Принцип разделения интерфейса
41%
Инверсия зависимостей
49%
Внедрение зависимости
24%
Инверсия управления
— AI сможет создавать сложные кодовые базы с нуля // Дарио Амадей CEO Anthripic
— Мы бы волновались, если бы он смог создавать простой код и не с нуля, а через рефакторинг, а так... Сложные и с нуля все могут.
— Мы бы волновались, если бы он смог создавать простой код и не с нуля, а через рефакторинг, а так... Сложные и с нуля все могут.
🧩 Тут две простейшие реализации языка LISP на JavaScript, одна ООП + паттерн Interpreter, а вторая на мультипарадигменном программировании, с тем же паттерном: https://github.com/HowProgrammingWorks/Interpreter/tree/main/JavaScript
Что думают функциональщики про GoF паттерны:
(GoF)(x) = G(F(x))
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM