Мне кажется что это вопрос не к Envoy, поскольку сам он вообще не умеет раздавать статику. Это практически чистый прокси. А потому поддержка всего, что вы описали зависит от того сервиса, который стоит за Envoy.
А если каналов будет 20? А если 50? И вы впервые видите этот код, а вам надо оперативно что-то исправить. А представитель заказчика (как назло) объясняет свою проблему обычными словами, а не блок-схемами на которых указаны правильные иксы и игреки. А блок-схему для этого кода почему-то не нашли (наверное автор её забрал с собой, когда увольнялся).
И конечно же автомат достаточно сложный. Его код минимуму на 3 экрана растягивается по высоте. Одним взглядом сразу не окинуть, и не увидеть что метод y25() вызывается не по тому условию. Там почему-то используется x23(), а надо x24() (наверное дети какие-то писали, которые не знают прописные истины).
Но это я слишком сильно далеко заглянул в будущее. Вы в этом время скорее всего ещё только запускаете дебагер, что бы по шагам разобраться в том как работает этот автомат, и у вас впереди есть один или даже два интересных дня, что бы это сделать. Что-бы заново нарисовать блок-схему и уже в ней найти ошибку, т.к. просто смотря на код её не увидеть.
Ох, поберегите мои нервы. Больно смотреть на ваше эгоистическое представление о красивом и читаемом коде. Вам может он и понятен. Но мне как человеку, который в первый раз его видит, трудно разбираться в этом месиве длинных однострочкиков с рандомным стилем именования сущностей.
Теперь у вас глобальная переменная automaton, и бесполезный класс PAirplane с сайд-эффектом в конструкторе (он меняет переменную automaton). Мне казалось что "класс ради класса" это особенность разработчиков на C# (там по другому нельзя) и в Java тоже любят всё делать классами, но даже в этом случае конструктор с сайд-эффектом — это привилегия новичков.
И ещё есть хитро спрятанная глобальная переменная ind, которая не первый взгляд просто какой-то счётчик внутри "event-loop-а", а на деле оказывается используется внутри метода класса PBSpider. Даю вам 5 балов за навык "минирования кода".
И ещё +1 бал за константы 4 и 33 для поля nState. Они мне нравятся, надо бы тоже почаще их везде пихать. Ещё я люблю 7. Я ведь могу в вашем коде поменять 4 на 7? Мне лично так понятнее будет, а то я 4 обычно для других целей использую.
Вы не добавили поле p_mainFSM в класс PBSpider, но при этом используете его в "евент-лупе". Но я вас понимаю — там же есть волшебная константа 4, которая железобетонно гарантирует, что мы сейчас имеем дело с экземпляром PSleep. Ведь все знают, что нельзя использовать 4 как значение состояния в других "автоматах" кроме PSleep.
В ваш код на C++ я даже не стал детально вникать. Для начала там где-то за кадром есть какой-то непонятный ВКП(а). Интернет предложил мне только "Всесоюзная Коммунистическая Партия".
Далее там какая-то шифровка в виде массивов двухсимвольных строк. И нет кода для его декодирования.
Ну и по мелочи — непонятно от куда взявшийся метод pFAwaitSleep->FCall(), которого нет в классе FAwaitSleep.
Что значит "блок схема генератора"? А какая блок схема у автомата? Абстрактного автомата.
О боже! «Горшочек, не вари!». Остановите кто-нибудь этот «автоматный генератор статей» похожих на написанное человеком.
Самолёты-пауки? Что это? Неужели нельзя было просто оставить «тех.задание» исходного примера, который вы позаимствовали, без изменений? Зачем притягивать за уши «самолёты», на код обычного «паука», который скачивает страницы из интернета?
Зачем вы вообще используете Python? Вы его абсолютно не знаете. Я даже уже сомневаюсь, что вы вообще программировать умеете. Была бы у меня возможность, я бы отобрал у вас питон и не давал пока не попросите прощения изучите его нормально по книгам и документации.
Я ещё в прошлой статье обратил ваше внимание на то, что вы используете в методах классов глобальные переменные. Но вы продолжаете писать абсолютную ересь, доводя её до абсурда. Теперь вы создали 3 одинаковых класса, которые используют внутри своих методов глобальный экземпляр ЭТОГО же самого класса. Как вообще у вас такая идея пришла в голову? Сами же потом оправдываете всё это незнанием языка и указателями (которых вообще в питоне, как языке программирования, нет). Прекратите писать о том, о чём не знаете. Изучите сначала язык, наберитесь в нём опыта, и только потом показывайте на публику свой код на нём.
И что вы вообще пытаетесь доказать своими статьям? Что автоматы — это какое-то лучшее решение чем async/await?
Только вот реализация async/await в питоне, в своей основе, сделана на генераторах. Генераторы — это просто синтаксический сахар для удобного написания итераторов. Итератор — это самый настоящий автомат. Генераторы позволяют проще писать и понимать код такого автомата, т.к. этот код не размазывается без необходимости по нескольким методам класса.
В итоге получается что код с async/await — это автомат. Просто он записан более понятным для людей образом без лишней «воды» в коде.
Зачем передавать ссылку на класс через аргументы? И как такое вообще можно сделать в C++, где класс не является объектом как в питоне?
Передавать надо экземпляр класса и сохранять его в "конструкторе" в поле экземпляра класса. Вот так:
По поводу наименования методов и переменных я категорически с вами не согласен. Мало того, что автоматный код (судя по вашим примерам) размазывает логику какого-то действия по разным методам, и собрать всё вместе не так просто. Так ещё эти x1, y1 точно не помогают понять, что именно делают эти методы, какая у них задача.
И хочется перефразировать известную фразу: "Вы пишете на питоне, но делаете это без уважения". Было бы полезно почитать рекомендации по оформлению кода и неймингу в языке программирования, прежде чем публично показывать ваш код на нём.
Лучше бы вы примеры в статье делали на C++, в котором, с ваших слов, вы разбираетесь лучше. Ваш код на Python откровенно плох.
"Однострочники", использование имён вида x1, y1, y2 и др. совершенно сбивает с толку и делает код ваших примеров непонятным.
И что это за использование внутри PTimer глобально созданного, мутабельного экземпляра PCount? У нас в команде за подобные вещи отрезают палец на ноге (шутка).
И что такое 4 в выражении self.nState = 4? Это какая-то очень известная константа про которую можно ничего не объяснять?
Да, я это заметил. Мои вопросы были риторическими, т.к. очевидно, что автор на них не ответит.
Переводчик видимо специалист в этой области, и ему было не очевидно, что этот материал плоховато справляется с «объяснением на пальцах» для начинающих.
Обратите внимание, что когда мы рассчитали все Z-баллы для каждого времени доставки пиццы и построили стандартную кривую нормального распределения
Где все эти расчёты? Как построили кривую?
Теперь, когда мы собрали несколько выборочных данных о времени доставки, мы выполнили расчет и обнаружили, что среднее время доставки больше на 10 минут с p-значением 0,03.
Где данные? Где расчёт? От куда все эти числа взялись?
Начиналось всё хорошо — лёгкий пример с пиццерией, понятные гипотезы с конкретными числами. А потом понеслось: пачка абстрактных определений, формулы с одними буквами, ни одного примера использования этих формул с подстановкой чисел. И в итоге: «Пиццерия нам врёт, потому что p=0.03 и это меньше чем 0.05».
Что бы админом зайти к нему в ресурсы и всё там сломать (шутка).
Или не админом, а просто другим пользователем, у которого есть разрешение на доступ (например член семьи). В общем тут та же история про "яйца в корзине". Одна "корзина" в api удобна для админского UI, а для пользовательского надо чётко, на уровне url, разделять ресурсы. Так проще реализовать доступ к "чужим" ресурсам — не надо лепить костыли для указания серверу, что Я не Я, а типа другой пользователь, который дал мне доступ.
И в логах понятнее становится к ресурсам какого юзера был запрос и какой (возможно другой) юзер сделал этот запрос.
Тут подходит аналогия с раскладкой папок в многопользовательских ОС — у каждого пользователя есть своя папка, а не все в одной ютятся.
Вы "сложили все яйца в одну корзину" и потом пытаетесь подпорками и if-чиками бить по рукам клиента, который потянулся не за своим яйцом.
Разделите "яйца" по отдельным "корзинам" и станет немного проще. Сделайте, например, /company_tasks и /emploee_tasks. Так и документация станет понятнее.
Я бы предложил вообще сделать вот так:
/<user_id>/company_tasks
/<user_id>/emploee_tasks
что бы еще точнее конкретизировать содержимое "корзин". Но я не в курсе насколько легко такое делать в DRF.
С роутингом по регекспам очень неудобно делать вложенные ресурсы т.к. не получается разнести в коде по разным ресурсам ответственность за доступ к его подресурсам. Приходится всю логику с проверками делать во вьюшке ресурса на который указывает url. Это в свою очередь мешает переиспользованию кода, т.к. в другом месте эту вьюшку не получится прикрутить из-за того, что там будут другие проверки и условия для извлечения того же самого ресурса (например надо получить задачу заказчика от лица исполнителя).
Для REST очень хорошо подходит механизм роутинга, который называется traversal. Но его нет в джанге и в DRF видимо тоже.
Не увидел в вашем примере ничего такого, что позволяло бы проще писать приложения с архитектурой REST. Хотя правильнее сказать — ничего такого, что заставляло бы писать этом стиле. Т.е. накладывало бы какие-то ограничения на программиста, которые исходят из ограничений описанных в REST.
У вас просто минималистичный web-фреймворк, который ни к чему не обязывает.
Предлагаю автору сравнить свой алгоритм сортировки ещё с Intellij Idea, Eclipse, Vim, Emacs (функция M-x::sort-lines) и обязательно с «Microsoft Notepad».
Само по себе значение ETag не так важно. Важен факт его изменения. А это несколько проще реализовать. Например хранить в отдельной таблице (или даже в чём-то вроде Redis) некий uuid или просто автоинкремент, генерируемый при каждом изменении данных.
Да, разновидность этой проблемы (добавление данных после начала "листания") в статье уже указана. Решать её надо другими методами, которые зависят от критичности этой проблемы. Например можно с каждой страницей возвращать некий ETag, который сможет показать клиенту, что данные, с момента начала листинга, изменились.
А в чём вы тут видите проблему? Если у вас в ТЗ указано условие, что данные надо сортировать по ID или по другому полю (которое укажет пользователь), то какая разница в каком реально порядке эти записи попали в базу? Значение имеет только то, что увидит пользователь. А при использовании сортировки он всегда увидит данные в строгом порядке.
Да, индекс по паре (sort_column, unique_column) и использование его для сортировки при паджинации — это подходящее решение. Но надо понимать, что оно увеличивает размер индексов (особенно если надо уметь сортировать по разным полям).
Снимаю своё замечание про метод FCall — не заметил, что у класса есть базовый класс.
А если каналов будет 20? А если 50? И вы впервые видите этот код, а вам надо оперативно что-то исправить. А представитель заказчика (как назло) объясняет свою проблему обычными словами, а не блок-схемами на которых указаны правильные иксы и игреки. А блок-схему для этого кода почему-то не нашли (наверное автор её забрал с собой, когда увольнялся).
И конечно же автомат достаточно сложный. Его код минимуму на 3 экрана растягивается по высоте. Одним взглядом сразу не окинуть, и не увидеть что метод
y25()
вызывается не по тому условию. Там почему-то используетсяx23()
, а надоx24()
(наверное дети какие-то писали, которые не знают прописные истины).Но это я слишком сильно далеко заглянул в будущее. Вы в этом время скорее всего ещё только запускаете дебагер, что бы по шагам разобраться в том как работает этот автомат, и у вас впереди есть один или даже два интересных дня, что бы это сделать. Что-бы заново нарисовать блок-схему и уже в ней найти ошибку, т.к. просто смотря на код её не увидеть.
Ох, поберегите мои нервы. Больно смотреть на ваше эгоистическое представление о красивом и читаемом коде. Вам может он и понятен. Но мне как человеку, который в первый раз его видит, трудно разбираться в этом месиве длинных однострочкиков с рандомным стилем именования сущностей.
Теперь у вас глобальная переменная automaton, и бесполезный класс PAirplane с сайд-эффектом в конструкторе (он меняет переменную automaton). Мне казалось что "класс ради класса" это особенность разработчиков на C# (там по другому нельзя) и в Java тоже любят всё делать классами, но даже в этом случае конструктор с сайд-эффектом — это привилегия новичков.
И ещё есть хитро спрятанная глобальная переменная ind, которая не первый взгляд просто какой-то счётчик внутри "event-loop-а", а на деле оказывается используется внутри метода класса PBSpider. Даю вам 5 балов за навык "минирования кода".
И ещё +1 бал за константы 4 и 33 для поля nState. Они мне нравятся, надо бы тоже почаще их везде пихать. Ещё я люблю 7. Я ведь могу в вашем коде поменять 4 на 7? Мне лично так понятнее будет, а то я 4 обычно для других целей использую.
Вы не добавили поле p_mainFSM в класс PBSpider, но при этом используете его в "евент-лупе". Но я вас понимаю — там же есть волшебная константа 4, которая железобетонно гарантирует, что мы сейчас имеем дело с экземпляром PSleep. Ведь все знают, что нельзя использовать 4 как значение состояния в других "автоматах" кроме PSleep.
В ваш код на C++ я даже не стал детально вникать. Для начала там где-то за кадром есть какой-то непонятный ВКП(а). Интернет предложил мне только "Всесоюзная Коммунистическая Партия".
Далее там какая-то шифровка в виде массивов двухсимвольных строк. И нет кода для его декодирования.
Ну и по мелочи — непонятно от куда взявшийся метод pFAwaitSleep->FCall(), которого нет в классе FAwaitSleep.
Что значит "блок схема генератора"? А какая блок схема у автомата? Абстрактного автомата.
Самолёты-пауки? Что это? Неужели нельзя было просто оставить «тех.задание» исходного примера, который вы позаимствовали, без изменений? Зачем притягивать за уши «самолёты», на код обычного «паука», который скачивает страницы из интернета?
Зачем вы вообще используете Python? Вы его абсолютно не знаете. Я даже уже сомневаюсь, что вы вообще программировать умеете. Была бы у меня возможность, я бы отобрал у вас питон и не давал пока не
попросите прощенияизучите его нормально по книгам и документации.Я ещё в прошлой статье обратил ваше внимание на то, что вы используете в методах классов глобальные переменные. Но вы продолжаете писать абсолютную ересь, доводя её до абсурда. Теперь вы создали 3 одинаковых класса, которые используют внутри своих методов глобальный экземпляр ЭТОГО же самого класса. Как вообще у вас такая идея пришла в голову? Сами же потом оправдываете всё это незнанием языка и указателями (которых вообще в питоне, как языке программирования, нет). Прекратите писать о том, о чём не знаете. Изучите сначала язык, наберитесь в нём опыта, и только потом показывайте на публику свой код на нём.
И что вы вообще пытаетесь доказать своими статьям? Что автоматы — это какое-то лучшее решение чем async/await?
Только вот реализация async/await в питоне, в своей основе, сделана на генераторах. Генераторы — это просто синтаксический сахар для удобного написания итераторов. Итератор — это самый настоящий автомат. Генераторы позволяют проще писать и понимать код такого автомата, т.к. этот код не размазывается без необходимости по нескольким методам класса.
В итоге получается что код с async/await — это автомат. Просто он записан более понятным для людей образом без лишней «воды» в коде.
Зачем передавать ссылку на класс через аргументы? И как такое вообще можно сделать в C++, где класс не является объектом как в питоне?
Передавать надо экземпляр класса и сохранять его в "конструкторе" в поле экземпляра класса. Вот так:
По поводу наименования методов и переменных я категорически с вами не согласен. Мало того, что автоматный код (судя по вашим примерам) размазывает логику какого-то действия по разным методам, и собрать всё вместе не так просто. Так ещё эти x1, y1 точно не помогают понять, что именно делают эти методы, какая у них задача.
И хочется перефразировать известную фразу: "Вы пишете на питоне, но делаете это без уважения". Было бы полезно почитать рекомендации по оформлению кода и неймингу в языке программирования, прежде чем публично показывать ваш код на нём.
Лучше бы вы примеры в статье делали на C++, в котором, с ваших слов, вы разбираетесь лучше. Ваш код на Python откровенно плох.
"Однострочники", использование имён вида x1, y1, y2 и др. совершенно сбивает с толку и делает код ваших примеров непонятным.
И что это за использование внутри PTimer глобально созданного, мутабельного экземпляра PCount? У нас в команде за подобные вещи отрезают палец на ноге (шутка).
И что такое 4 в выражении
self.nState = 4
? Это какая-то очень известная константа про которую можно ничего не объяснять?Переводчик видимо специалист в этой области, и ему было не очевидно, что этот материал плоховато справляется с «объяснением на пальцах» для начинающих.
Где все эти расчёты? Как построили кривую?
Где данные? Где расчёт? От куда все эти числа взялись?
Начиналось всё хорошо — лёгкий пример с пиццерией, понятные гипотезы с конкретными числами. А потом понеслось: пачка абстрактных определений, формулы с одними буквами, ни одного примера использования этих формул с подстановкой чисел. И в итоге: «Пиццерия нам врёт, потому что p=0.03 и это меньше чем 0.05».
Что бы админом зайти к нему в ресурсы и всё там сломать (шутка).
Или не админом, а просто другим пользователем, у которого есть разрешение на доступ (например член семьи). В общем тут та же история про "яйца в корзине". Одна "корзина" в api удобна для админского UI, а для пользовательского надо чётко, на уровне url, разделять ресурсы. Так проще реализовать доступ к "чужим" ресурсам — не надо лепить костыли для указания серверу, что Я не Я, а типа другой пользователь, который дал мне доступ.
И в логах понятнее становится к ресурсам какого юзера был запрос и какой (возможно другой) юзер сделал этот запрос.
Тут подходит аналогия с раскладкой папок в многопользовательских ОС — у каждого пользователя есть своя папка, а не все в одной ютятся.
Вы "сложили все яйца в одну корзину" и потом пытаетесь подпорками и if-чиками бить по рукам клиента, который потянулся не за своим яйцом.
Разделите "яйца" по отдельным "корзинам" и станет немного проще. Сделайте, например, /company_tasks и /emploee_tasks. Так и документация станет понятнее.
Я бы предложил вообще сделать вот так:
/<user_id>/company_tasks
/<user_id>/emploee_tasks
что бы еще точнее конкретизировать содержимое "корзин". Но я не в курсе насколько легко такое делать в DRF.
С роутингом по регекспам очень неудобно делать вложенные ресурсы т.к. не получается разнести в коде по разным ресурсам ответственность за доступ к его подресурсам. Приходится всю логику с проверками делать во вьюшке ресурса на который указывает url. Это в свою очередь мешает переиспользованию кода, т.к. в другом месте эту вьюшку не получится прикрутить из-за того, что там будут другие проверки и условия для извлечения того же самого ресурса (например надо получить задачу заказчика от лица исполнителя).
Для REST очень хорошо подходит механизм роутинга, который называется traversal. Но его нет в джанге и в DRF видимо тоже.
Не увидел в вашем примере ничего такого, что позволяло бы проще писать приложения с архитектурой REST. Хотя правильнее сказать — ничего такого, что заставляло бы писать этом стиле. Т.е. накладывало бы какие-то ограничения на программиста, которые исходят из ограничений описанных в REST.
У вас просто минималистичный web-фреймворк, который ни к чему не обязывает.
Нуу, тут можно книгу написать по этой теме. Всё зависит от требований к системе и имеющихся ресурсов. Варианты навскидку:
Само по себе значение ETag не так важно. Важен факт его изменения. А это несколько проще реализовать. Например хранить в отдельной таблице (или даже в чём-то вроде Redis) некий uuid или просто автоинкремент, генерируемый при каждом изменении данных.
Да, разновидность этой проблемы (добавление данных после начала "листания") в статье уже указана. Решать её надо другими методами, которые зависят от критичности этой проблемы. Например можно с каждой страницей возвращать некий ETag, который сможет показать клиенту, что данные, с момента начала листинга, изменились.