Лаборатория Математики и Программирования Сергея Бобровского – Telegram
Лаборатория Математики и Программирования Сергея Бобровского
1.29K subscribers
1.19K photos
24 videos
931 links
ЛаМПовое с Бобровским
Download Telegram
Весьма достойный в целом материал из вики "Composition over inheritance", разошедшийся по куче статей и учебников, где приведена большая диаграмма наследования из известного учебника по паттернам Фрименов, который я рекомендую начинающим, но в котором, например, самый важный паттерн Visitor вообще не упоминается.

Но посмотрите, тут например Duck выполняет композицию с интерфейсами Flyable и Quackable, а не наследуется от них. Но вы что, собираетесь создавать свободно плавающий экземпляр Flyable в своём проекте? лол

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

P.S. Честно говоря, в целом таксономия -- это дурацкая затея. Все таксономии кривые и почти всегда заводят в тупик. Ваши категории всё равно будут совершенно неверными, и все будут спорить по каждому поводу. Такой вещи, как иерархия наследования, не существует. И тем не менее, вам надо уметь хорошо их готовить. В СильныхИдеях скоро будет материал на эту тему, как тут правильно рассуждать. Вы все наверняка слышали рекомендацию "предпочитайте композицию наследованию", что, как правило, хороший совет, однако есть случаи, когда этот совет неприменим.
👍73🫡3
Цель каждой строки кода - сделать какой-то факт истинным. Сложность кода вытекает из того, насколько трудно установить факт из того, что уже является истиной.

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

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

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

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

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

Композиция вместо этого работает только с интерфейсом внешнего класса и будет надёжной.
🫡5🔥3
В 2022-м мировой рынок AI составлял 136 млрд. долл., а к концу текущего десятилетия он вырастет в 13 (!) раз. Уже в ближайшие 2-3 года работу из-за AI потеряет 85 млн. человек, но появится 97 млн. новых (вроде промпт-инженеров).

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

Сейчас те, кто шустро пилят AI-стартапы, делают сразу по 3-5 проектов одновременно, потому что сегодня они устаревают за считанные месяцы. Вообще, очень интересный тренд: старые стартаперские схемы "сделать нетленку" в расчёте выпуска долгоиграющего продукта на годы, безнадёжно устарели. Сроки создания продуктов с помощью AI ускорились в десятки раз, и это лишь начало, и парадигма ИТ-инноваций меняется более чем полностью:
- создаём за пару недель уже не прототип, а нечто работающее,
- потом продаём этот сервис несколько месяцев и на эти деньги пилим что-то другое,
- потом появляется куча бесплатных аналогов, текущий проект сдыхает, а мы тем временем запускаем новые.
Аджайл-подходы наконец-то становятся естественным культом.

Например, что произойдет с криптоиндустрией, когда миллиарды экземпляров продвинутой версии AutoGPT будут управлять параллельной экономикой BTC? Когда стремительно развиваются такие децентрализованные сети, как Lightning?
11🤔7
Разработка AI продвигается невероятными темпами, и меня постоянно спрашивают испуганные непрограммисты

С чего мне начать??

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

Сейчас доступны десятки гайдов "как писать промпты", коллекции из сотен промптов на все случаи, есть даже нейросетки, которым даёшь короткий тупой запрос, а они выдают подробный детальный промпт для AI. Это всё хорошо, но лучше всего развивать мета-навык: самому учиться писать эффективные промпты по любым темам, без подсказок. Хорошо в этом помогут курсы по системной инженерии, например.

-- Чёткая цель: формулируете, что именно вы хотите получить, с однозначными подробными инструкциями на хорошем английском, осознавая, что AI не может "думать" (его архитектура в принципе не приспособлена для логических рассуждений), хотя и может -- в определённых пределах -- "понимать";

-- Ограничения (пожалуй, самое важное, но сильно недооценённое): что вы не хотите получить (если вы не укажете, что AI не должен делать, то скорее всего получите что-то весьма далёкое от вашей цели, и затем будете долго мучиться многими итерациями);

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

P.S. Надежды на то, что AI в ближайшие 20 лет (а может, и гораздо быстрее) не лишит работы подавляющее количество людей за Земле (98%), примерно аналогичны надеждам того парня, который верил, что википедия и мир опенсорса никогда не будут существовать, потому что дескать никто не станет работать бесплатно, а большинство людей в любом случае глупы.
12🫡2👍1🔥1
"Intelligent Machines and Idiotic Humans: A Startup Story"
(идеи для AI-стартапов)

Серия 7. 10 идей по масштабированию стартапа, состоящего из одного человека, с помощью AI

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

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

Вот 5 возможных тем (всё это с помощью API OpenAI, GPT4ALL или подобных)

1. Интеллектуальная платформа для создания контента: генерируем материалы для блогов, статьи, посты в социальных сетях и т. д., и предлагаем такие услуги, как контент-стратегия, SEO-оптимизация, таргетинг аудитории и анализ эффективности.

2. Автоматизированная платформа, генерирующая маркетинговые кампании (электронные письма, посты в социальных сетях, рекламные объявления), дополнительно A/B-тестирование, аналитика, управление кампаниями и персонализация на основе данных о клиентах.

3. Юридическая помощь на базе ИИ: Сервис, объединяющий AI с юридическими базами данных, в помощь организациям грамотно создавать контракты, соглашения, юридические записки, а также предоставлять юридические консультации в режиме реального времени.

4. Конструктор резюме: Сервис для составления резюме и сопроводительных писем в соответствии с конкретными описаниями вакансий. Дополнительные функции могут включать подбор вакансий, инструктаж под собеседования и карьерные советы.

5. Помощь здравоохранению: Формирование возможных диагнозов на основе симптомов + поддержка психического здоровья :)
Можно интегрировать с электронными медицинскими картами для персонализации.
👍10🔥1
6. AI- репетитор: персонализированная помощь в обучении, подробные ответы на вопросы, объяснение концепций по ряду предметов. Дополнительные услуги могут включать составление учебных планов, аналитику обучения и рекомендации ресурсов.

7. SaaS-платформа автоматизации взаимодействия с клиентами по различным каналам (чат, электронная почта, социальные сети). Дополнительные услуги могут включать анализ настроений клиентов, их профилирование и прогнозное моделирование оттока клиентов.

8. Перевод и локализация (в России почти 300 языков и диалектов): мгновенный перевод текстов, а также услуги по локализации -- культурная адаптация контента, SEO на разных языках и консультации по региональному маркетингу.

9. Бизнес-аналитика: анализ данных и предоставления адекватных выводов. Дополнительные услуги могут включать предиктивное моделирование, обнаружение аномалий, визуализацию данных, и даже генерацию аналитических SQL-запросов.

10. Ну, всяческая помощь программистам в реальном времени, автоматическая генерация кода, поиск багов, отладка, тестирование, предложения по оптимизации кода. Дополнительные функции могут включать управление проектами, code review и т. п.

Некоторые из этих уже у нас появились, но конкуренция нулевая.

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

Или всё вышеперечисленное.

И вы можете брать наценку пропорционально создаваемой бизнес-ценности (например, 10,000 рублей в месяц для небольшой ниши, где не особо сложно найти 100 корпоративных клиентов).
🔥5👍3🤔1
Между прочим, согласно легендарному стандарту IEEE-754 (арифметика с плавающей запятой), и нули и бесконечности в языке программирования должны уметь быть с явным знаком. То есть должны явно различаться и +0.0 и -0.0 , которые с одной стороны, равны, но с другой стороны, их знак должен учитываться в некоторых функциях (каком-нибудь арктангенсе).

Например, в Python результаты -1.0 / float('inf') и +1.0 / float('inf') получатся соответственно -0.0 и +0.0, которые "в целом" равны, но "в деталях" использования могут давать разные результаты.

P.S. До массовой поддержки IEEE-754 всё было совсем печально.
🔥13👍2🫡2
Кент Бек (автор XP и TDD) внезапно взялся продавать воркшопы по системному мышлению.

Молюсь, чтобы со мной никогда ничего подобного бы не случилось.

Желаю Беку, чтобы он не скатился ещё ниже, до каких-нибудь курсов по раскрытию внутренних резервов :)
🤯63👏1
Действительно, сейчас такой тренд, что "эксперты по web3" спешно переквалифицировываются в "экспертов по AI" 😂
🔥9🫡2🤔1👌1
Вы написали метод из 30 строк. В нём вы замечаете фрагменты, которые вроде бы выполняют более мелкие действия. Разбиваете ли вы этот метод на более мелкие методы, по SRP?

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

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

Но здесь есть простой приём, когда вы можете и рыбку съесть, и косточкой не подавиться, рассказываю курсантам в СильныхИдеях.
👍7🤔5🔥1🫡1
Ну, да, такое случается с многими каждый раз, когда они решают поизучать гомотопическую теорию типов. Причём, когда вы хотите узнать побольше о HoTT, то ожидаете 690 страниц теории категорий, но на самом деле получаете 890 страниц Agda :)

И в целом, теоркат на пути к HoTT совсем не первый, не второй и не третий шаг.

Иначе вы не въедете в теоркат на уровне универсальных пропертей вроде UMP.
🤔5🤯42
Это примерно тот "архитектурный" уровень, которому вы в итоге научитесь на массовых курсах по программированию и веб-фреймворкам за 100 тысяч рублей :)
💯135🔥5👍2🤔2
Ну ладно, хорошо, учат вот такому, более "продвинутому" 🙈 ^^^
🤝11👍6😇3👏2👌2
Регулярно советую учиться понимать код крупных проектов, разбираясь прежде всего в используемых структурах данных, и сам этим регулярно занимаюсь. И хотя это хорошо работает в одних случаях, но чаще всего я в итоге обнаруживал, что полностью заблудился.

И тут я понял: несмотря на то, что я внимательно просмотрел все определения структур данных в некотором крупном проекте, я не понял, что они означают в контексте системы в целом. Я могу например разобраться (или даже в редких случаях увидеть в комментах), что "связь между кластерами определяется временем создания, буферами отправки и приёма и собственно коннектом", довольно хорошо понимая, что такое эта связь между кластерами и что с ней можно делать, однако в этом проекте куда чаще активно используются такие термины, как "лист" (и не в смысле дерева), а также множество неопределённых терминов; например, не то что никакой информации мне не дало, а скорее даже больше запутало изучение структуры "SharedItem", которая, как оказалось, имеет Id, содержимое и представление. Ну и?

В хорошей документации имеется несколько частей, которые я рекомендую изучать новичкам в первую очередь. Прежде всего это руководство по ключевым файлам (синтаксическим единицам) и структурам данных (семантическим единицам). Однако больше всего хотелось бы увидеть некоторую карту/раскладку имён -- объяснения смысла и цели часто используемых идентификаторов в коде проекта.
🔥12👍43
Многие современные API существуют десятилетиями (например, Windows API наглядный пример). Чем шире используется система, и чем больше требуется совместимости между версиями, тем ситуация печальнее. Например, есть такая глобальная система бронирования авиабилетов SABRE, API которой существует уже 60 лет ))) и если у вас когда-либо был неудачный опыт работы с авиакомпанией, есть шанс, что частично это было связано с её API.

Когда на ваше API завязано множество сторонних ИТ-систем, вы, возможно, уже никогда не сможете изменить поведение вашего API.

Недавно консультировал небольшую команду по теме дизайна API (в области AI, ага :), и в процессе придумал один очень простой, очень поучительный и очень наглядный use case, который считаю особенно умным ))) Скоро расскажу курсантам в СильныхИдеях. Посмотрев на 5 строчек кода (определение типа), вы сразу поймёте важный принцип проектирования долгосрочно развивающихся API.
🔥11🫡31
Заметка на хабре про SOLID -- классический пример
отсутствия университетского образования незнания фундаментальных основ, когда изучаешь темки поверхностно as is, без понимания принципов, заложенных в их основу (SOLID например уже как следствие разбираем на моём треке по ООАП).

А кто просто почитал по SOLID статейки уровня википедии и пытается их бездумно применять, так и будет всю жизнь жутко косячить, думая что SRP - это вот такое =>

"Рассмотрим персонажа ролевой игры (RPG). Он может обладать такими возможностями, как перемещение, атака, взаимодействие с окружающей средой и отображение анимации. Придерживаясь SRP, можно было бы разделить эти функциональные возможности на отдельные классы, такие как CharacterMovement, CharacterCombat, CharacterInteraction и CharacterAnimation."

)))
🔥65🏆21
О языках с выразительными системами типов обычно говорят: "Если оно проверяет типы, то, вероятно, всё работает". Это происходит, в частности, с чистыми функциями с полиморфными типами -- тут в итоге получается столь мало вещей, которые можно сделать с каждым входом, что иногда единственная разумно выглядящая функция, которую удаётся написать, и становится единственно верной. То есть, в некоторых случаях можно просто сгенерировать функцию из сигнатуры типа.

Например, есть такая штука, как джанглоид -- кусочек кода, который синтезируется автоматически и выполняет некоторый условно клиентский запрос к API на основании заданных типов входных и выходных значений. Так вот, формальная теория джанглоидов была разработана в начале 2000-х, задолго до явления хипстерских AI-ассистантов. Джанглоиды отлично комбинируются, и на их основе для Eclipse (основной Java IDE того времени) был разработан плагин, который выдавал адекватные подсказки и варианты кода, и, в частности, нашёл решение 18 из 20 задач.
"Jungloid mining: helping to navigate the API jungle"

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

Но есть важный и контринтуитивный нюанс в понятии "чётко описывать типы". Этот момент тоже разбираем в СИ, потому что чем конкретнее тип, тем, парадоксальнее, большее количество реализаций он допускает. И наоборот, чем больше тип -- "дженерик", чем более он абстрактный, тем меньшее количество реализаций возможно.

=

Духовным наследником джанглоидов стал красивый проект SyPet

"SyPet will automatically find a sequence of API calls from these Java libraries that will pass all test cases provided by the programmer. "
но к сожалению тоже заброшен 5 лет назад.

Затем эти алгоритмы были расширены на полиморфные типы: проект Hoogle+, автоматическая генерация программы на Haskell на основе их сигнатур.
hoogleplus.goto.ucsd.edu
hoogle_plus
🔥21👍1
В России вчера был официально запущен Mos.Hub -- типа, импортозамещённый аналог гитхаба.

Внимание, вопрос:

- он тоже работает под Microsoft Windows?

-- используют ли Mos.Hub разработчики Mos.Hub для создания Mos.Hub?

-- и, в частности, может ли Mos.Hub откатить Mos.Hub чтобы пофиксить Mos.Hub, когда Mos.Hub сбойнул?
🤔17👏2🫡2🔥1😇1
Наследование -- это создание новой реализации на основе старой. Аналогично, вы расширяете интерфейс, просто добавляя ещё пару методов. Никакого наследования.

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

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

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

Вообще, наследование это труднейшая часть теории объектов. Обвинять кого-то, что он "не понимает наследование" всё равно, что обвинять его, что он "не понимает алгебру/пространства Chu применительно к квантовой физике".
🫡11👍4
Вообще, есть единственный стратегический вопрос, которого следует придерживаться в любом проекте, и ответу на который я стараюсь учить: Как мы можем сделать это правильно?

Если вы осознанно не атакуете сложность, она обязательно будет атаковать вас.
👍10🔥5