Обновить

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

После первого же примера кода расхотелось читать дальше:

private static ITelegramBotClient _botClient;
private static ReceiverOptions _receiverOptions;

А зачем это поля, а не переменные? Почему они статические?

using var cts = new CancellationTokenSource();

Зачем создавать CancellationTokenSource, если вы его никогда не активируете?

await Task.Delay(-1);

...а выходить из программы не надо?

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

Нет никакой проблемы. Подобных статей написано на разных ресурсах, включая хабр, огромное количество и все они под копирку. Но помимо хабра и статей, если другие источники, в которых можно посмотреть как и что делается и как делают другие люди.
Тем более у dotnet хорошее комьюнити у которого всегда можно поспрашивать вопросы и попросить примеры.
ИМХО более управляемо и понятнее стартовать бота подобным образом:
https://github.com/ImoutoChan/GreenCaptchaBot
https://github.com/ForNeVeR/Megadeth
И в дальнейшем будет более проще им управлять (например, прикрутить админку или сорт оф)

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

А те кто знают и умеют, но допускают ошибки - пишут и получают шишки.

Так это же хорошо. Смысл "шишек" в том, чтобы люди, которые допускают ошибки, исправлялись, а те, которые читают - видели, что это ошибки, и так делать не надо.

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

...а выходить из программы не надо?

Ctrl+C или простое закрытие консоли уже не работает ?

Зачем создавать CancellationTokenSource, если вы его никогда не активируете?

Он используется в старте бота, в обработчике апдейтов и ошибок, а также его можно использовать, чтобы остановить бота, например, поставить while(!cts.Token.IsCancellationRequested)

Он используется в старте бота, в обработчике апдейтов и ошибок

Нет, не используется. Все, что вы делаете - это передаете токен (не source) в StartReceiving. Но поскольку вы никогда не активируете сам CancellationTokenSource, это совершенно бесполезно, и можно с тем же успехом передать CancellationToken.None.

также его можно использовать, чтобы остановить бота, например, поставить while(!cts.Token.IsCancellationRequested)

Где и зачем?

Вместо await Task.Delay(-1); ставим этот цикл и по какой-нибудь команде используем cts.Cancel . Про сам source я понял, спасибо.

Вместо await Task.Delay(-1); ставим этот цикл

Кажется, вы не особо работали с cooperative cancellation.

var task = _botClient.ReceiveAsync(UpdateHandler, ErrorHandler, _receiverOptions, cts.Token);
// [...]
await task;

По крайней мере, вы так не будете бесполезно тратить ресурсы в заблокированном потоке.

по какой-нибудь команде используем cts.Cancel .

По какой? Где?

Кажется, вы не особо работали с cooperative cancellation.

Верно, я вообще по сути новичок, и учусь на всяких бесплатных ресурсах.

По крайней мере, вы так не будете бесполезно тратить ресурсы в заблокированном потоке.

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

По какой? Где?

Можно сделать консольные команды. Можно сделать админ-меню (админ-команду) в самом боте.

Верно, я вообще по сути новичок, и учусь на всяких бесплатных ресурсах.

Может быть тогда не стоит использовать в статьях, где вы учите других, то, что вы еще не знаете?

Ну так здесь бот запуститься и тут же выключится.

С чего бы?

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

Нам ничего не нужно. За цикл поллинга отвечает библиотека, которую вы используете.

Можно, конечно, переписать на вебхуках, но я, к сожалению, так не умею.

Так на вебхуках ничего не изменится ровным счетом (с этой точки зрения).

Можно сделать консольные команды. Можно сделать админ-меню (админ-команду) в самом боте.

Слушайте. Типовое решение такого "админ-меню" - это

Console.WriteLine("Press Enter to exit...);
Console.ReadLine();
cts.Cancel();

Пойнт в том, что это ставится вместо вашего бесконечного цикла или await. Угадайте, почему.

Может быть тогда не стоит использовать в статьях, где вы учите других, то, что вы еще не знаете?

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

Нам ничего не нужно. За цикл поллинга отвечает библиотека, которую вы используете.

Она не блокирует основной поток, если не ставить никакие блокирующие циклы, то код запуститься и тут же завершится. А вот эта часть кода:

var task = _botClient.ReceiveAsync(UpdateHandler, ErrorHandler, _receiverOptions, cts.Token);
// [...]
await task;

вообще работать не будет, так как методStartReceiving (в вашем случае ReceiveAsync, и это важно, дальше поймете почему, я не просто придираюсь) имеет тип void , и как нам тогда ожидать завершения этого метода ?

Слушайте. Типовое решение такого "админ-меню" - это

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

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

да, его [токен] можно не указывать, но так лучше не делать, иначе могут быть проблемы при следующих запусках бота

Это как так? Что за проблемы? Каким образом передача токена, который вы никогда не активируете (т.е. полностью эквивалентного CancellationToken.None), избавляет от этих проблем?

Она не блокирует основной поток [... ] методStartReceiving (в вашем случае ReceiveAsync, и это важно, дальше поймете почему, я не просто придираюсь) имеет тип void

Метод ReceiveAsync имеет тип Task, и в его описании прямым текстом написано "This method will block if awaited.`

и как нам тогда ожидать завершения этого метода ?

await task;

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

В том, что человек, читающий вашу статью, не знает, что это надо сделать и как это делать.

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

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

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

Вот я и рассказываю.

Метод ReceiveAsync имеет тип Task, и в его описании прямым текстом написано "This method will block if awaited.`

Тут проблема ровно обратная, на самом деле. Вопреки тому, что написано в документации ("Starts receiving Updates on the ThreadPool, invoking HandleUpdateAsync for each."), в реальности оно запускается в том же треде. Так что разделение на присвоение и await имеет мало смысла (там нет yield потока), первый вызов заблокирует неизвестно насколько (и, например, не будет показано сообщение "я запущен").

Ctrl+C или простое закрытие консоли уже не работает ?

Конечно, нет. Это аварийное закрытие программы, а надо обрабатывать еще и нормальное.

А как ? Я всегда использую ctrl + c :D

А как ?

...что конкретно?

Я всегда использую ctrl + c

И когда ваш бот крутится на сервере, там он тоже закрывается по Ctrl-C?..

Это намекает нам на то, что вам не очень важен graceful shutdown.

...что конкретно?

Ну вы говорите, что я делаю неправильно, я спрашиваю: как сделать правильно ?

И когда ваш бот крутится на сервере, там он тоже закрывается по Ctrl-C?..

Да, а про graceful shutdown я вообще впервые слышу, как бы печально это не было.

Ну вы говорите, что я делаю неправильно, я спрашиваю: как сделать правильно ?

А это напрямую зависит от того, как вы хотите запускать (и хостить) свой бот.

Да

То есть ваши боты на сервере в продакшне крутятся как интерактивное консольное приложение? Серьезно?

А это напрямую зависит от того, как вы хотите запускать (и хостить) свой бот.

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

То есть ваши боты на сервере в продакшне крутятся как интерактивное консольное приложение? Серьезно?

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

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

Так в продакшне делать не надо никогда.

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

Официальная документация MS - нет? Откуда, вы думаете, у меня информация берется?

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

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

вы наверное с марса?

Нет, я с бэкенда.

лет 25 как всегда код завершают через ctrl+c

Вот вам всего несколько примеров, когда код завершается не через Ctrl-C:

  • при остановке контейнера, докер шлет главному процессу образа SIGTERM

  • при остановке сервиса Windows, SCM шлет сервису команду Stop

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

  • когда окружение AWS Lambda собирается положить рантайм лямбды, оно возвращает событие Shutdown в ответ на запрос следующего события (а потом шлет SIGKILL, если они затянули процесс)

  • наконец, банальные git log и git add -i в качестве нормативного выхода ожидают клавишу q

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

в этой статье нет ни контейнеров ни сервисов ни IIS и много чего другого

Вы же написали "всегда код завершают".

это просто приложение для обучения

А в приложениях для обучения ставят ReadLine, чтобы закрывалось детерминировано и с graceful shutdown.

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

Это не энциклопедическое, это приложения, с которыми я повседневно работаю (кроме сервисов Windows, они мне перестали быть нужны лет 5-10 назад). Вот systemd для меня да, энциклопедическое знание, я под него никогда не интегрировал.

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

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

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

У меня он тоже вызывает вопросы. А вот у автора поста - нет.

То есть вы, ваш опыт и то с чем работали вы это хорошо, а другого просто не бывает?

Почему же? Другое вполне себе бывает. Но в случае с .NET я, мне кажется, видел все основные способы развертывания сервисов.

Я вам озвучил свои кейсы и опыт

А вот кстати нет, не озвучили вы свои "кейсы" (ну или я их пропустил/забыл в этой большой дискуссии, что возможно, к сожалению). То, что я знаю про вас - это то, что

  • вы "не пересекаетесь" с продакшн-кодом

  • вы пишете на 4.8 и (Windows?) Forms в 99% случаев

о чем спор-то?

О том, как корректно обрабатывать завершение сервисов в .NET.

Что вы где-то нашли сервис который висит с активным окном и ждёт команду?

Вообще, я не знаю, откуда вы это взяли. Я такого не говорил.

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

В общем как я понял вы к академической среде не имеете никакого отношения

...интересно, из чего вы сделали такой (ошибочный, кстати) вывод?

Предлагаю им и оставаться, как учитель вы никогда не состоитесь.

Некоторое количество успешно отучившихся у меня курсов с вами не согласятся.

Обучение написанию бота на C#

Хм, я не знал, что вы это считаете кейсом. Ну ладно, окей.

Это вам нужно читать статью - управление сервисами в .NET

Зачем мне ее читать? Я-то это знаю в достаточной мере.

Когда висит окно с запущенной консольной программой и её нужно прервать - жмут на Ctrl+C.

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

Вы же пишете о том, что этого делать не нужно

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

именно вы заговорили про сервисы, хотя это отдельный класс приложений Windows

Сервисы, демоны - все, что крутится в фоне, не важно, в Windows или в Linux. (обратите внимание, что автор статьи пишет под линукс).

то есть вы в своих кейсах где-то находите окна сервисов [...], а потом завершаете их работу любым другим способом кроме Ctrl+C

Нет, ничего такого я не делаю. Зачем?

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

Вот приблизительно так и должен быть запущен бот.

А ваш кейс абсолютно непонятен.

Какой конкретно мой кейс? Я пока вижу только что-то, что вы себе придумали.

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

Но вам это не нужно

Я, в общем-то, прямым текстом озвучил свои задачи: меня в первую очередь интересует не обучение автора, а то, чтобы читатели статьи видели, каких ошибок не надо совершать. Эта задача личной перепиской не решается.

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

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

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

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

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

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

просто у вас вместо 1-11 классов был бы только универ да еще для тех у кого опыта вагон и тележка.

Ничего не понял. "Только универ" вместо 1-11 классов? А?

Вы не сможете остановить корректно программу не имеющую такого механизма.

Какого механизма?

Аналогия

Ваша аналогия мне не понятна.

А у вас к обучающему коду требования как к презентации Apple.

Нет. Я уже описал свои требования к обучающей статье.

Должны, да не обязаны, особенно в формате обучалки.

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

Тогда чем вас так не устраивает Ctrl+C в конкретно взятом примере?

Тем, что нет гарантии, что бот не потеряет сообщения.

Да кто бы спорил.

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

Возможно именно в Линуксе это не обязательно, но в винде именно так.

...автор, кстати, пишет для линукса.

Это не ошибки, а допущения.

Допущения - это когда автор обучающего материала знает, как надо, но сознательно упрощает для целей урока. А автор статьи, по его собственному признанию, не знает, что такое graceful shutdown, и как же должно быть сделано.

Ну а вещи типа никогда не активируемого CancellationTokenSource - это просто ошибки, без оговорок на какие либо допущения.

Почитайте книжки, пример я вам уже приводил.

Пример книжки? Хм... Что-то я не нашел этого в ваших сообщениях.

Тем, что нет гарантии, что бот не потеряет сообщения.

Тривиальный демонстрационный пример:

try
{
    Console.WriteLine("Started");
    while (true)
    {
        Thread.Sleep(1000);
        Console.Write(".");
    }
}
catch (Exception e)
{
    Console.WriteLine(e.ToString());
}
finally
{
    Console.WriteLine("Exited");
}

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

Сравните поведение с кодом ниже при нажатии Enter (собственно, можно после этого сравнивать поведение при Enter и при Ctrl-C)

try
{
    using var cts = new CancellationTokenSource();

    Console.WriteLine("Started");

    var task = Task.Run(() =>
    {
        while (!cts.IsCancellationRequested)
        {
            Thread.Sleep(1000);
            Console.Write(".");
        }
        Console.WriteLine();
        Console.WriteLine("Task finished");
    });

    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
    cts.Cancel();
    await task;
}
catch (Exception e)
{
    Console.WriteLine(e.ToString());
}
finally
{
    Console.WriteLine("Exited");
}
НЛО прилетело и опубликовало эту надпись здесь

А, так вам пофигу на потерю данных в боте. Тогда понятно.

Мне, очевидно, не пофигу.

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

Да блин, да не бот это, это обучалка

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

как там причесать код и сделать завершение работы ДЕЛАЙТЕ САМИ

Так откуда читатель статьи узнает, (а) что это вообще надо сделать, и (б) как это сделать?

нафига в статье это вообще показывать?

А "нафига вообще" писать статью "как пользоваться библиотекой X", если у библиотеки X есть (очень неплохая, кстати, лучше, чем у многих) документация?

(замечу, что в этой документации есть пример, аналогичный тому, который статье автора, и в нем нет этой ошибки, а указано решение приблизительно аналогичное моему)

А "нафига вообще" писать статью "как пользоваться библиотекой X", если у библиотеки X есть (очень неплохая, кстати, лучше, чем у многих) документация?

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

При этом, в этой статье минимальное количество менее интересных для меня моментов про корректное завершение процесса, логгирование и другие, безусловно важных, но в данном контексте совершенно лишних телодвижений. Вас почему-то не возмутило наличие кучи switch/case кострукций…

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

Вас почему-то не возмутило наличие кучи switch/case кострукций…

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

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

PS

Прочитал статью и узнал, что это довольно легко.

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

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

Корректного.

Корректного механизма, делающего что?

Абсолютно пофигу, нажму Ctrl-C и всё норм.

Так мы и выяснили, что для вас потеря данных - норм.

А стоит такая задача?

В общем случае - да.

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

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

Это игра в слова не меняющая сути.

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

Исправит, не вижу проблемы.

До сих пор не исправил.

Мне кажется было бы нагляднее если бы код раскидали по методам хотя бы. Вся логика в одном методе это такое себе.

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

Похоже вы никогда не видели и не пытались изменить внутренность .Select() размером в 300+ строк.

а мне ООП тем и не нравится что раскидывается по одной строчке по миллиону методов и вообще непонятно что и зачем.

Это не ООП, это плохой код. Вы про структурное программирование не слышали?

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

я как раз и пишу таким способом,

Каким "таким"?

я пишу про ООП, а не про код автора (уж не знаю с чего вы решили что я пишу про него)

Я тоже не про код автора.

так как комментирующий NCNecros как раз и хотел бы видеть код написанный в стиле ООП.

Цитирую дословно: "было бы нагляднее если бы код раскидали по методам хотя бы". Это не про ООП, это про структурное программирование.

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

Я, вроде, нигде не упоминал процедурное программирование, я оба раза написал о структурном.

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

Тот код который выложил автор уже написан по принципам структурного программирования

Я вроде бы и не говорил обратного.

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

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

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

так написано всё ООПэшное

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

по собственной статистике скажу, что в среднем на одну позицию информации в ООП приходится 5-7 строк кода, в процедурном 1.5

К сожалению, без формальной методики подсчета это исключительно ваше субъективное мнение.

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

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

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

Тот же "Hello World!" в ООП из одной строки превращается в 20. При этом класс helloworld уже размещают в другом файле. При вызове сначала создает объект скласса helloworld, а потом вызывают метод который выводит текст на экран.

Я просто оставлю это здесь:

using System;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Это вот прямо из шабона приложение. И это я еще не стал брать новый .NET, где есть top-level statements.

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

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

Когда мои утверждения субъективны, они и не требуют доказательств. Просто теперь явно видно, что ваше утверждение "так написано всё ООПэшное" - субъективно.

Это 25 лет работы, личная статистика, она субъективна, кто бы спорил, но она такая.

Личная статистика за 25 лет легко может быть предвзятой.

Нет. Именно поэтому я никак и не могу начать пользоваться ООП, потому что там совсем всё иначе, нужно пересматривать сам подход к реализации

Почему вы настойчиво приравниваете декомпозицию к чему-то другому? Теперь вот к реализации.

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

Вы все равно упрётесь в то, что в ООП вы будете делать а в процедурном - нет, в обязательном порядке.

Нет, не упрусь. Я просто не буду раскидывать код по одной строчке ни в одном, ни в другом случае.

Но это не ООП

Почему вдруг?

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

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

то есть формализация кода увеличивает его на 1100%, не меняя сути, об этом и речь.

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

Посмотрите исходники разных библиотек в Nuget, они все +- одинаковые.

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

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

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

В ООП очень много конструкций которые вы никак и никогда не перенесёте в процедурное исполнение

...зачем бы?

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

а для вас это сразу не понятно и требуется говорить явно?

Да, для меня это сразу не понятно.

и? вы ссылаетесь на личную статистику, я ссылаюсь, что не так?

И... ничего. Просто полезно это помнить.

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

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

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

Будете

...нет? Нет, не буду. С чего вы взяли.

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

Нет, не будет.

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

в остальном случае пишут так чтобы было "по книжке".

В реальном продакшн-коде? Далеко не всегда.

речь не о "зачем"

Нет, речь как раз о "зачем". Зачем мне переносить конструкции из ООП в процедурный код?

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

Тогда вы ничего не напишете в ОО.

Тогда получается, что за последние несколько лет я ничего не написал. Хм. Люди, которые пользуются результатами работы этого "ничего", очень удивятся.

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

Подождите. Если "все знают", то зачем мне писать, что конкретно и где? Все же и так знают?

А вы когда читаете обучающий код всегда ожидаете увидеть нанотехпологичиный квантовый портал или щепотку говнокода с детскими ошибками?

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

Для переноса на платформу где ООП в принципе нет. Для работы с языком в котором нет ООП.

Зачем мне это? По работе от меня это не требуется.

В целом для себя, чтобы не задуряться этим ООП.

"Для себя" я ФП изучаю, мне это интереснее.

Еще печальнее что нет переносимости между 4.8 и Core и .NET.

Учитывая, что я несколько лет занимаюсь миграцией с 4.8 на более новые версии, мне это забавно слышать. Есть там переносимость, пусть и не один в один. А с Core 3.1 на более новые версии и того проще мигрировать, это я проделывал несколько раз достаточно рутинно.

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

о том что для этого нужно будет изучать обе платформы, что мне, например, неинтересно

Не, ну если неинтересно, нет задачи - то незачем, да. Это не значит, что нет переносимости, это значит, что вам незачем тратить усилия на перенос. Это тоже нормально.

У нас вот есть понимание, зачем нам это нужно, вот мы и тратим на это ресурсы.

Только если его пишет специалист соответствующего уровня.

А когда обучающий текст пишет не-специалист, получается плохой обучающий текст. Поэтому не-специалистам такие тексты писать не стоит.

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

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

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

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

Ну а теперь расшифрую: "все знают" относится к словам о том, что "с новыми версиями всё легче", и не более того.

"Это понятно". А что же я не хочу, по вашим словам, писать?

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

я с 3.1 на 4.8 переделывал одну штуку

В смысле - с Core 3.1? Ну так это же бэкпорт, он не обязан поддерживаться.

Специалистам не стоит считать что у них есть право на что-то указывать.

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

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

Со мной это не сработает, я 25 лет работаю со студентами и они всё понимают прекрасно.

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

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

Даже если предположить, что это так - а что, должен?

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

У нас в универе таких просто единицы.

Если не секрет, что конкретно вы преподаете? Просто любопытно.

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

рукалицо, причем здесь это...

При том, что вы это зачем-то сюда притащили. Вы, не я.

Нет, но тогда откуда претензии к тем кто делится?

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

Маркетинг на кафедре экономики и Теорию и технологию программирования на кафедре информационных технологий.

Спасибо.

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

Благодарю! Это моя первая статья, боялся, что будет что-то непонятно)
Скоро выпущу вторую часть этой статьи :З

Меня больше в таких программах интересует параллельное выполнение, и многопоточность (ведь как я понял тут "закидываются" в твой код на колбэки, не дожидаясь ответов?!)

Являются ли все созданные объекты от этой библиотеки потокобезопасными?

в отличии от придирчивости @lair

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

Например, что будет если в момент отправки одного ответа придет следующий "вопрос"?

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

это вопрос к Дурову, я не знаю как именно сервер ТГ обрабатывает запросы.

Сервер ТГ тут не при чем - он, очевидно, имеет достаточную степень паралеллизма, особенно учитывая, что их заведомо больше одного.

И главное - как вы своим кодом можете на это влиять.

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

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

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

Ровно те, которые заданы в стартовом комменте треда: как поведет себя код в описанных условиях.

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

Аудитория 150 млн человек. После поста в первые 20 секунд больше лайков чем у Леди Гаги около ~270k + прибавляем все остальные выше перечисленные действия.

Что я должен делать? Твой код подойдет для меня (ИлонМаска)?

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

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

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

Какой API?

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

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

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

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

это вопрос финансов

Предположительно, если мы пишем на аудиторию в 150 млн. человек, то финансы на мощности есть. Что возвращает нас к вопросу "как написать код, чтобы он справлялся".

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

вы уверены?

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

мне кажется тут код для домашнего знакомства с ботами в ТГ.

Так про это выше и спрашивали: если у меня такая аудитория, тогда мне подойдет этот код? Ответ "нет, не подойдет" (который ниже дал автор) - тоже ответ, вполне честный.

и вы непременно критерием качества статьи у человека написавшего в обучающем newbie формате хотите заполучить код со всеми фишками и плюшками?

Нет. Для меня одним из критериев качества будет то, что ограничения кода, приведенного для обучения, будут упомянуты (а принятые решения - объяснены). А если у меня создается ощущение, что автор обучающей статьи сам не знает какие-то вещи, которые в статье использует, доверия такое статья у меня будет меньше.

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

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

Чтобы люди, которые ее прочитают, не совершали те же ошибки, которые совершает автор.

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

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

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

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

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

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

Не хотите писать совсем.

Но вообще да, вы правы, не хочу. У меня нет иллюзий, что мне есть, что рассказать в формате статьи. Все, что я знаю - это тривиальный опыт, почерпнутый из большого количества разрозненных источников и не меньшего количества дебага очень специфических случаев, актуальных для меня, но не актуальных для широкой публики. Ну вот знаю я, допустим, как запустить ASP.NET Core внутри vanilla ASP.NET внутри IIS...и что? Кому, кроме меня (и моего работодателя) это надо? И это еще не считая количества согласований на NDA, которые придется пройти.

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

Вы уж определитесь: "ваши статьи никому не будут интересны" или "напишите один раз правильную статью".

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

Я, как видно выше, уже определился.

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

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

"Как обрабатывать многопоточность" - это как раз вполне себе теоретическая база.

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

"Другой" по сравнению с чем? Базовая конкурентность и асинхрония в .net сейчас... базовая. Никак не выше миддла. Более того, даже джуниорам по ней придется ходить неизбежно, главное, с тропинки не сходить.

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

В современном .net если захотеть просто сделать HTTP-запрос, это станет темой номер 1. Собственно, весь основной API в библиотеке, которую использует автор поста, асинхронный, так что если не уметь работать с task-based asynchrony, можно влететь в проблемы (как, например, с CancellationToken).

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

Вы в учебнике по бейсику предлагаете начать не с PRINT "HELLO WORLD!", а с A=USR("j2k_3ijsxcP{Phfewuhoi")

Нет, не предлагаю. Вы мне приписываете что-то, что я не говорил.

В данном коде все будет работать последовательно, параллельной работы программы нет. Чтобы код работал в параллельном режиме, нужно использовать треды (thread) или таски (task), я предпочитаю таски, ставлю Task.Run в UpdateHandler и все работает прекрасно.

Добрый день! Разобрались в итоге как быть с параллельной обработкой? Ведь, если просто воткнуть Task.Run, есть вероятность, что ответы начнут приходить юзеру не в том порядке, если он пишет быстро, а действия в ответ на запрос занимают разное время. Может заводите очереди под юзеров на бэке?

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

Интересно было бы посмотреть как это вяжется с ИИ, а не хардкод «ответ-вопрос». Есть над чем подумать в продолжении данной темы. В целом есть немного замечаний по коду, так как чувствуется немного универских винформ, но для начала пойдет. Также вопрос насколько система будет работать с полным потоком пользователей? Были ли мысли об этом на этапе разработки?

В смысле вяжется с ИИ ? Немного не понял вопроса. Продолжение обязательно будет.

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

Честно говоря, в универе меня учили только C и после C++, C# я учу сам, используя разные ресурсы (книги, видеоуроки, статьи, интернет-материалы), поэтому я был бы очень рад получать критику моему коду, чтобы совершенствоваться!

Также вопрос насколько система будет работать с полным потоком пользователей? Были ли мысли об этом на этапе разработки?

Конкретно этот пример работает в последовательном режиме, параллельности тут нет, но ее легко добавить. В следующей статье обязательно рассмотрим этот пример. Насчет пользователей, за моей спиной уже несколько ботов и пока полеты отличные, пользователей не так много, где-то 500-1000 на бота и все отлично. Может, при увеличении пользователей где-то будут провалы, но пока все стабильно.

где-то 500-1000 на бота и все отлично

Тут вопрос не в том, сколько пользователей на бота. Тут вопрос в том, сколько сообщений в квант времени.

Привет всем как человеку который базово знает C Sharp и который до этого работал на Python со схожими библиотеками по Telegram ботам (тоже базово) хочу сказать что сам урок сделан довольно-таки неплохо лично я понял практически всё и хочу сказать что я был бы рад если выйдет продолжение особо не понимаю Почему так много людей так сильно придираются к этому уроку ведь, ну базово тут всё довольно-таки понятно А все ошибки - Это мелочи

Уже было много статей по написанию простейшего бота.

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

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

Попробуйте почитать здесь https://t.me/TurboBotsChannel
Фреймворк использует классическое ООП для генерации страниц, позволяет получить доступ к SQLite БД, хранить файлы в собственном частном Телеграм канале, принимать оплату в Telegram Stars. На базе этого фреймворка уже написано семейство ботов.

Автору большое спасибо, дал вектор куда и как работать с библиотекой!!! Ты главное донес смысл работы с библиотекой!

PS А на умников не обращай внимания, всегда найдется кто захочет выделиться из толпы! А нормальный программер, молча сам напишет свой код и просто скажет спасибо!

Спасибо!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации