Как стать автором
Обновить

От input() к UI после вводного курса по Python

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров5.2K

Неоригинальное начало.

Начинающий python разработчик недавно попросил меня посмотреть "что нужно улучшить" в программе, написанной им по гайду “Python с нуля”. Таких гайдов, курсов и туториалов доступно великое множество.

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

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

В чем проблема? Интерфейс пользователя.

Конечно, в коде были участки для рефакторинга. Где ж и их нет. 

Но зададим себе вопрос: а вы бы хотели пользоваться таким приложением?  Ответ очевиден - нет. И причина в UI (интерфейсе пользователя). 

Консольные интерактивные интерфейсы пользователя были актуальны для mainframe в 80-х годах прошлого века, а то и ранее. 

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

Ближайшим аналогом разработанного приложения являются утилиты командной строки для управления пользователями операционной системы. Системному администратору хорошо. А вот обычным пользователям такое приложение “не зайдет”.

Где tutorial по самому крутому UI? Не крутой, а доступный тебе для освоения.

Казалось бы решение лежит на поверхности. 

 Не надо усложнять
Не надо усложнять

Но почему в ходе учебного курса предложили сделать именно такой интерфейс? 

Все просто. Консольный интерфейс с использованием вызовов input() крайне прост по своей сути. Это позволяет обучающемуся сосредоточиться на понимании базовых структур данных и конструкций языка.

Ограничение в скорости усвоения знаний.

Сложность использования технологий растет до тех пор, пока не найдется способ "упаковаться" внуть фреймворка или библиотеки. Но и упаковка не 100% панацея
Сложность использования технологий растет до тех пор, пока не найдется способ "упаковаться" внуть фреймворка или библиотеки. Но и упаковка не 100% панацея

Современные ИТ-технологии не сразу стали такими. С каждым витком развития происходило их усложнение. В какие то моменты времени “сложность пряталась” внутрь библиотек и фреймворков. 

Даже общее понимание идей и концепций при наличии готовых библиотек требует времени.

А скорость усвоения знаний человеком весьма конечна

Применительно к нашему кейсу: изучив базовый курс по Python, у новичка не получится в короткий срок научиться делать интерфейсы общения с пользователем на естественном языке, как у ИИ.

Вряд ли получится сделать современный Web интерфейс на React/Vue.js и аналогичных Javascript фреймворках. 

Может быть получится сделать классический Web интерфейс c генерацией статичного HTML на серверной стороне. 

А вот десктоп приложение с графическим оконным интерфейсом (GUI) сделать скорее всего получится.

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

Выбираю GUI-библиотеку и делаю? Рано. Хороший фасад не бывает без хорошей изнанки.

GUI приложение станет сложнее, чем консольное. К этому нужно приготовиться.

Хочешь писать сложные программы - учись их структурировать.

А.П. Чехов. Несуществующие цитаты из сети интернет.
А.П. Чехов. Несуществующие цитаты из сети интернет.

Структура GUI приложения. Разделяй и властвуй.

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

Постарайся понять подход и идею.

Годная структура  GUI приложения. Не догма
Годная структура GUI приложения. Не догма

Фронтальная часть приложения (front или фронт) занимается отображением и вводом данных пользователя.

Подложка (back или бэк) реализует логику обработки данных. В нашем случае создание, удаление, редактирование, получение и хранение списка пользователей.

Фронт про отображение, бэк про логику обработки.

Бэк состоит из:

  • Model - набор сущностей предметной области. В нашем случае одна сущность User (Пользователь).

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

  • Validator - логика проверки корректности единичной сущности. Используется Service.

  • Repository - хранилище списка пользователей. Используется Service

Структура приложения является разновидностью паттерна проектирования MVC (Model-View-Controller)

Кончай дедукцию, давай продукцию.

С целью и способом достижения определились. Пора начинать реализацию.

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

Продолжу данный подход и в статье.

Какие знания обновить.

Потребуется обновить (или приобрести) базовые знания ООП (объектно-ориентированного программирования): класс, конструктор класса, методы, поля, понимание наследования. 

Полезно иметь начальные знания по теме модулей в python. Желательно уметь пользоваться type hints.

Модель и валидатор. На страже корректности полей.

Модель (model) состоит из одного класса User.

class User:
  def __init__(self, id: int, first_name: str, last_name: str):
    self.id = id # уникальный идентификатор пользователя
    self.first_name = first_name # имя пользователя
    self.last_name = last_name # фамилия пользователя

Валидатор (validator) - Проверяет фамилию и имя на заполненение данными и наличие целочисленного id у пользователя.

class UserValidator:
  def validate(self, user: User):
    # Проверки:
    # Имя и фамилия должны быть непустой строкой 
    # без цифр и спец символов
    # id должно быть целым числом
    ... 
    return [] # вернуть пустой список, если ошибки не обнаружены

Репозиторий. Храни и выбирай.

Исходная программа хранила список пользователей в памяти. Был реализован репозитарий (repository) - обертка над питоновским списком с автогенерацией id пользователя при вставке.

class UserRepository:
  def add_user(self, user: User): 
    # сгенерировать id, user.id = gen_id
    # сохранить пользователя в списке
    pass
  def update_user(self, user: User):
    # если пользователь не найден по id, то ошибка
    pass
  def delete_user(self, user: User):
    pass
  def list_all(self):
    # вернуть список пользователей
    pass
  def find_by_id(self, id: int) -> User | None:
    # Найти пользователя по id
    pass
  def find_by_names(self, first_name: str, last_name: str):
    # True - есть пользователь с таким именем и фамилией, иначе False 
    pass

Сервис бэку голова.

Сервис (service) - Реализует возможность создания, редактирования, удаления пользователя, а также получение списка пользователей. Использует валидатор и репозиторий.

class UserService:
  def __init__(self, validator: UserValidator, repo: UserRepository):
    self.validator = validator
    self.repo = repo

  def create_user(self, first_name: str, last_name: str):
    user = User(0, first_name, last_name)
    errors = self.validator.validate(user)
    # Если найдены ошибки в атрибутах пользователя, 
    # то вернуть ошибку
    ...
    founded_user = repo.find_by_names(first_name, last_name)
    # если пользователь с именем и фамилией уже есть - ошибка
    ...

    # все ок. добавляем пользователя в список пользователей
    self.repo.add_user(user)

    return user
  
  def update_user(self, user: User):
    # Проверть, что пользователь с id есть в списке
    existed_user = self.repo.find_by_id(user.id)
    if existed_user is None:
      ...
    # проверить валидность обновляемого пользователя
    errors = self.validator.validate(user)
    if len(errors) > 0:
      ...

    # проверить, что нет пользователя с другим id, 
    # но таким же именем и фамилией
    self.repo.find_by_names(user.first_name, user.last_name)
    
    self.repo.update_user(user)
  
  def delete_user(self, user: User):
    pass
  
  def list_all_users(self):
    return self.repo.list_all()

В качестве промежуточного результата консольное приложение было отрефакторено для использования бэка без изменения консольного UI.

Библиотека UI. PySide.

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

Главный экран GUI был написан с помощью виджета QtTable, кнопок QPushButton. Формы создания и редактирования пользователя построены на базе QDialog.

Трудности первых шагов были успешно преодолены.

Что в итоге? Шаг из 80-х в 90-е за три недели.

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

Стало ли приложение лучше? Да.

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

Является ли предложенный путь "единственно правильным"? Нет. Всего лишь один из вполне рабочих вариантов.

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

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

Хороших новостей больше:

  • Писать десктопные приложения не так страшно. Хотя и далеко не всегда актуально.

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

Куда дальше? Полезные ссылки и идеи.

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

Развитие "глазами пользователя".

  • После закрытия программы данные пропадают, так как хранятся только в памяти. Смотреть в сторону встраиваемых баз данных, например, SQLLite или "взрослой" БД PostgreSQL. Полезно изучить SQL.

  • Необходимы улучшения UI - меню, popup меню, inplace edit итд. Материалов по PyQt/PySide в сети много. Какой из них лучше трудно сказать. Выбирайте сами. Как один из примеров читать тут.

  • Способ распространения приложения - скачивание из интернет с установкой python на машину пользователя. Неудобно. Можно посмотреть в сторону PyInstaller и Nuitka для сборки в исполняемый файл.

Развитие "глазами программиста".

Дорожные карты прокачки навыков

Развитие кейса

Теги:
Хабы:
Всего голосов 6: ↑3 и ↓3+2
Комментарии21

Публикации

Работа

Data Scientist
43 вакансии

Ближайшие события