From e9fb5ff4d4ce4b6aa85ad6d6672615b4cb09e524 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 17 Oct 2018 12:33:04 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D1=8F=D1=81=D0=BD=D1=8F=D1=8E=D1=89=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=82=D0=B5=D0=BA=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 7ad73b2c..58e23870 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ безгранично гибкий код — это как сферический конь в вакууме. Теоретически возможен, но практической ценности не несет. +Если мы заранее будем знать как изменятся требования к коду через год, два или +десять лет, то уже сейчас можно заложить необходимые механизмы расширения +функциональности. К сожалению, такие сведения сложно получить, а зачастую +просто невозможно. Приходится опираться на свой опыт, опыт товарищей, +прорабатывать разные сценарии развития проекта, подстраховываться. + Один из часто встречающихся и оправданных приемов — это отделение обработки данных от процесса ввода/вывода. Рассмотрим несколько примеров. @@ -108,3 +114,10 @@ days_before_start ? 1)от источника данных; 2)от формата вывода в файл. +Кроме того, часть кода удалось превратить в чистые функции, что облегчит +тестирование и повторное использование. + +Стратегия по отделению операций ввода/вывода от обработки данных встречается +повсеместно, в самых разных программах: от небольших скриптов до серьезных и +крупных проектов. Это один из базовых приемов, нужно уверенно им владеть. + From 52a1d2b42b14cd16e1b6a5d2b36b0cf7c751f898 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 17 Oct 2018 12:33:38 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58e23870..5a2b6610 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ days_before_start ? 1)от источника данных; 2)от формата вывода в файл. -Кроме того, часть кода удалось превратить в чистые функции, что облегчит +Кроме того, часть кода удалось превратить в [чистые функции](https://devman.org/encyclopedia/decomposition/decomposition_pure_functions/), что облегчит тестирование и повторное использование. Стратегия по отделению операций ввода/вывода от обработки данных встречается From 4846789cce2932f1eae848269be88efd106e3eae Mon Sep 17 00:00:00 2001 From: Alina Date: Wed, 17 Oct 2018 12:34:44 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D0=BA=D0=B0=D1=80=D1=82=D0=B8=D0=BD=D0=BA=D1=83?= =?UTF-8?q?=20=D1=81=D0=BE=20=D1=81=D1=85=D0=B5=D0=BC=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7ad73b2c..c26851c5 100644 --- a/README.md +++ b/README.md @@ -108,3 +108,4 @@ days_before_start ? 1)от источника данных; 2)от формата вывода в файл. +![alt text](https://devman.org/assets/images/7_40__data_flow.png) \ No newline at end of file From 4fb288681d3dac182c839de6afd30812775372d3 Mon Sep 17 00:00:00 2001 From: dvmn-tasks <44063469+dvmn-tasks@users.noreply.github.com> Date: Tue, 7 Jul 2020 15:10:43 +0300 Subject: [PATCH 04/11] Update image link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c26851c5..d3c84658 100644 --- a/README.md +++ b/README.md @@ -108,4 +108,4 @@ days_before_start ? 1)от источника данных; 2)от формата вывода в файл. -![alt text](https://devman.org/assets/images/7_40__data_flow.png) \ No newline at end of file +![image](https://dvmn.org/filer/canonical/1594117412/678/) From abd0aa56d7131565ea38b9b422c858c40a46bd3d Mon Sep 17 00:00:00 2001 From: Oleg Date: Mon, 1 Dec 2025 18:52:40 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B8=20=D0=B2=D1=8B=D0=B4=D0=B5=D0=BB=D0=B8=D0=BB=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4d77e670..035d118b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Отделяйте ввод/вывод от обработки +## Отделяйте ввод/вывод от обработки Ключевой критерий качества кода — это стоимость внесения в него изменений. @@ -16,12 +16,13 @@ Один из часто встречающихся и оправданных приемов — это отделение обработки данных от процесса ввода/вывода. Рассмотрим несколько примеров. -Пример. Подбор онлайн-курса +### Пример. Подбор онлайн-курса По условию задачи нужно скачать из сети данные об онлайн-курсах, выбрать из них лучшие и сохранить результат в xlsx файл. Вот фрагмент кода: +``` def get_courses_list(courses_url): html = fetch_html(courses_url) if html: @@ -30,6 +31,8 @@ def get_courses_list(courses_url): else: print("can't load list of courses") exit() +``` + Теперь примерим на себя роль провидца и подумаем какой функционал потребуется через месяц: @@ -38,26 +41,27 @@ def get_courses_list(courses_url): В случае если адрес недоступен - постучаться по другому url в зеркало сайта. В случае ошибки сделать запись в лог и взять данные из ранее подготовленного кеша. -Как все это сделать когда def get_courses_list сама завершает программу ?! От -вызова exit() надо отказаться. Можно выбросить исключение и таким образом +Как все это сделать когда `def get_courses_list` сама завершает программу ?! От +вызова `exit()` надо отказаться. Можно выбросить исключение и таким образом сообщить о проблеме внешнему коду, пускай там разбираются. -Вызов print тоже стоит вынести из тела функции наружу. В рассмотренных +Вызов `print` тоже стоит вынести из тела функции наружу. В рассмотренных сценариях вывод в консоль зависит от общей логики загрузки данных и -многократных вызовов def get_courses_list. +многократных вызовов `def get_courses_list`. -Что еще может потребоваться в скором будущем? +### Что еще может потребоваться в скором будущем? Отладить и покрыть тестами парсер HTML страницы. Ускорить работу скрипта, хранить ранее скачанные страницы в кеше на жестком диске. -Ага, значит вызывать fetch_html() внутри def get_courses_list не такая уж +Ага, значит вызывать `fetch_html()` внутри `def get_courses_list` не такая уж хорошая идея. Жить будет легче если передать в def get_courses_list строку с HTML разметкой вместо courses_url. Вуаля, мы решили проблемы еще до их появления на горизонте! -Пойдем дальше. Код другой функции: +**Пойдем дальше. Код другой функции:** +``` def get_course_info(html): # ... parsing logic @@ -71,6 +75,8 @@ def get_course_info(html): # .... parsing logic return course_data +``` + Что может произойти с кодом дальше? Если рейтинга нет — надо искать его на другом сайте. @@ -78,11 +84,12 @@ def get_course_info(html): Отчет о курсах без рейтинга выгружать в дополнительную вкладку xlsx, чтобы удобнее было руками проверять. Для всего этого нужно уметь отличать от прочих ситуацию "рейтинг неизвестен". -В Python для этих целей предусмотрено значение rating = None. А строку "No +В Python для этих целей предусмотрено значение `rating = None`. А строку "No rating yet" можно переместить туда где данные подготавливаются к выводу в xlsx. -Та же функция, часть вторая, последняя: +**Та же функция, часть вторая, последняя:** +``` def get_course_info(html): # ... more parsing logic is here @@ -94,19 +101,21 @@ def get_course_info(html): '4_weeks': duration, "5_rating": rating } +``` + Сразу возникают вопросы. А если нужна еще одна выгрузка в формате csv, с -другим порядком столбцов, как это сделать? Как заменить столбец 2_date на -days_before_start ? +другим порядком столбцов, как это сделать? Как заменить столбец `2_date` на +`days_before_start` ? Кроме того, наперед известно, что пользовательский интерфейс — будь то вывод в консоль или запись в файл — меняется очень часто. Было бы удобно собрать все, что относится к форматированию вывода в одном месте. Например, всю логику -выгрузки в xlsx поместить в def fill_xlsx(workbook, courses):, а вывод в -консоль собрать внутри if __name__=='__main__':. Удастся избежать вычитывания +выгрузки в xlsx поместить в `def fill_xlsx(workbook, courses):`, а вывод в +консоль собрать внутри `if __name__=='__main__':`. Удастся избежать вычитывания и повторной отладки всей программы от начала до конца, ведь изменения локальны и изолированы. -Вместо заключения +### Вместо заключения В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: From 5aea5d261ccc9638fdb451b15a8a685fc0cfcc77 Mon Sep 17 00:00:00 2001 From: Oleg Date: Mon, 1 Dec 2025 19:05:17 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Внёс изменения в заголовки и оформление текста. Добавил оформление списков. --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 035d118b..04d17fea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Отделяйте ввод/вывод от обработки +## Ввод/вывод vs Обработка данных Ключевой критерий качества кода — это стоимость внесения в него изменений. @@ -49,13 +49,14 @@ def get_courses_list(courses_url): сценариях вывод в консоль зависит от общей логики загрузки данных и многократных вызовов `def get_courses_list`. -### Что еще может потребоваться в скором будущем? +#### Что еще может потребоваться в скором будущем? -Отладить и покрыть тестами парсер HTML страницы. -Ускорить работу скрипта, хранить ранее скачанные страницы в кеше на жестком +* Отладить и покрыть тестами парсер HTML страницы. +* Ускорить работу скрипта, хранить ранее скачанные страницы в кеше на жестком диске. + Ага, значит вызывать `fetch_html()` внутри `def get_courses_list` не такая уж -хорошая идея. Жить будет легче если передать в def get_courses_list строку с +хорошая идея. Жить будет легче если передать в `def get_courses_list` строку с HTML разметкой вместо courses_url. Вуаля, мы решили проблемы еще до их появления на горизонте! @@ -77,12 +78,13 @@ def get_course_info(html): return course_data ``` -Что может произойти с кодом дальше? +_Что может произойти с кодом дальше?_ -Если рейтинга нет — надо искать его на другом сайте. -В xlsx указывать не просто отсутствие рейтинга, а еще на каких сайтах искал. -Отчет о курсах без рейтинга выгружать в дополнительную вкладку xlsx, чтобы +1. Если рейтинга нет — надо искать его на другом сайте. +2. В xlsx указывать не просто отсутствие рейтинга, а еще на каких сайтах искал. +3. Отчет о курсах без рейтинга выгружать в дополнительную вкладку xlsx, чтобы удобнее было руками проверять. + Для всего этого нужно уметь отличать от прочих ситуацию "рейтинг неизвестен". В Python для этих целей предусмотрено значение `rating = None`. А строку "No rating yet" можно переместить туда где данные подготавливаются к выводу в xlsx. @@ -120,8 +122,8 @@ def get_course_info(html): В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: -1)от источника данных; -2)от формата вывода в файл. +* от источника данных; +* от формата вывода в файл. Кроме того, часть кода удалось превратить в [чистые функции](https://devman.org/encyclopedia/decomposition/decomposition_pure_functions/), что облегчит тестирование и повторное использование. From 91040c3e60966c8669b8317f682f903d1541b3d8 Mon Sep 17 00:00:00 2001 From: Oleg Date: Sun, 7 Dec 2025 21:21:06 +0300 Subject: [PATCH 07/11] =?UTF-8?q?=D0=9E=D1=80=D0=B3=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=81=D1=82=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1d74e219 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ diff --git a/README.md b/README.md index 04d17fea..69e913d0 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,12 @@ данных от процесса ввода/вывода. Рассмотрим несколько примеров. ### Пример. Подбор онлайн-курса - +*** По условию задачи нужно скачать из сети данные об онлайн-курсах, выбрать из них лучшие и сохранить результат в xlsx файл. Вот фрагмент кода: -``` +```python def get_courses_list(courses_url): html = fetch_html(courses_url) if html: @@ -49,10 +49,10 @@ def get_courses_list(courses_url): сценариях вывод в консоль зависит от общей логики загрузки данных и многократных вызовов `def get_courses_list`. -#### Что еще может потребоваться в скором будущем? +**Что еще может потребоваться в скором будущем?** -* Отладить и покрыть тестами парсер HTML страницы. -* Ускорить работу скрипта, хранить ранее скачанные страницы в кеше на жестком +1. Отладить и покрыть тестами парсер HTML страницы. +2. Ускорить работу скрипта, хранить ранее скачанные страницы в кеше на жестком диске. Ага, значит вызывать `fetch_html()` внутри `def get_courses_list` не такая уж @@ -62,7 +62,7 @@ HTML разметкой вместо courses_url. Вуаля, мы решили **Пойдем дальше. Код другой функции:** -``` +```python def get_course_info(html): # ... parsing logic @@ -78,7 +78,7 @@ def get_course_info(html): return course_data ``` -_Что может произойти с кодом дальше?_ +**Что может произойти с кодом дальше?** 1. Если рейтинга нет — надо искать его на другом сайте. 2. В xlsx указывать не просто отсутствие рейтинга, а еще на каких сайтах искал. @@ -91,7 +91,7 @@ rating yet" можно переместить туда где данные по **Та же функция, часть вторая, последняя:** -``` +```python def get_course_info(html): # ... more parsing logic is here @@ -118,7 +118,7 @@ def get_course_info(html): и изолированы. ### Вместо заключения - +*** В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: From 868b887e87e36125ebc83b40afd0f4125a8c5bd5 Mon Sep 17 00:00:00 2001 From: Oleg Date: Sun, 7 Dec 2025 21:22:44 +0300 Subject: [PATCH 08/11] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=BB=20=D0=BE?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=82=D1=8C=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 69e913d0..bdcb5934 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ данных от процесса ввода/вывода. Рассмотрим несколько примеров. ### Пример. Подбор онлайн-курса -*** По условию задачи нужно скачать из сети данные об онлайн-курсах, выбрать из них лучшие и сохранить результат в xlsx файл. Вот фрагмент кода: @@ -118,7 +117,6 @@ def get_course_info(html): и изолированы. ### Вместо заключения -*** В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: From 51760c05a24a0b1001cee3def7e8d25c39ea2197 Mon Sep 17 00:00:00 2001 From: Oleg Date: Sun, 7 Dec 2025 21:23:33 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=A3=D0=B2=D0=B5=D0=BB=D0=B8=D1=87?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bdcb5934..9f2c470c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Ввод/вывод vs Обработка данных +# Ввод/вывод vs Обработка данных Ключевой критерий качества кода — это стоимость внесения в него изменений. @@ -16,7 +16,7 @@ Один из часто встречающихся и оправданных приемов — это отделение обработки данных от процесса ввода/вывода. Рассмотрим несколько примеров. -### Пример. Подбор онлайн-курса +## Пример. Подбор онлайн-курса По условию задачи нужно скачать из сети данные об онлайн-курсах, выбрать из них лучшие и сохранить результат в xlsx файл. Вот фрагмент кода: @@ -116,7 +116,7 @@ def get_course_info(html): и повторной отладки всей программы от начала до конца, ведь изменения локальны и изолированы. -### Вместо заключения +## Вместо заключения В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: From c7966fe9bd152f411c55c9bf780dfb0590df3bd8 Mon Sep 17 00:00:00 2001 From: Oleg Date: Sun, 7 Dec 2025 21:29:33 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B2=D1=91=D0=B7=D0=B4=D0=BE=D1=87=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D1=86=D0=B8=D1=84=D1=80=D1=8B=20=D0=B2=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f2c470c..18ef6a77 100644 --- a/README.md +++ b/README.md @@ -120,8 +120,8 @@ def get_course_info(html): В результате мы пришли к ситуации, когда логика обработки данных слабо зависит: -* от источника данных; -* от формата вывода в файл. +1. от источника данных; +2. от формата вывода в файл. Кроме того, часть кода удалось превратить в [чистые функции](https://devman.org/encyclopedia/decomposition/decomposition_pure_functions/), что облегчит тестирование и повторное использование. From 21fa8dcf94fc5346067f2b93992f3cb57b0e8420 Mon Sep 17 00:00:00 2001 From: Oleg Date: Sun, 7 Dec 2025 23:02:55 +0300 Subject: [PATCH 11/11] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18ef6a77..74d44ae2 100644 --- a/README.md +++ b/README.md @@ -123,11 +123,11 @@ def get_course_info(html): 1. от источника данных; 2. от формата вывода в файл. +![image](https://dvmn.org/filer/canonical/1594117412/678/) + Кроме того, часть кода удалось превратить в [чистые функции](https://devman.org/encyclopedia/decomposition/decomposition_pure_functions/), что облегчит тестирование и повторное использование. Стратегия по отделению операций ввода/вывода от обработки данных встречается повсеместно, в самых разных программах: от небольших скриптов до серьезных и крупных проектов. Это один из базовых приемов, нужно уверенно им владеть. - -![image](https://dvmn.org/filer/canonical/1594117412/678/)