Научная статья на тему 'ПРИМЕНЕНИЕ ШАБЛОНА ПРОЕКТИРОВАНИЯ ВНЕДРЕНИЯ ЗАВИСИМОСТЕЙ ДЛЯ РАЗРАБОТКИ ИНТЕРНЕТ-ПРИЛОЖЕНИЙ НА ОСНОВЕ ПРОГРАММНОГО КОМПЛЕКСА DEPENDENCY INJECTOR'

ПРИМЕНЕНИЕ ШАБЛОНА ПРОЕКТИРОВАНИЯ ВНЕДРЕНИЯ ЗАВИСИМОСТЕЙ ДЛЯ РАЗРАБОТКИ ИНТЕРНЕТ-ПРИЛОЖЕНИЙ НА ОСНОВЕ ПРОГРАММНОГО КОМПЛЕКСА DEPENDENCY INJECTOR Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
124
15
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
ВНЕДРЕНИЕ ЗАВИСИМОСТЕЙ / ШАБЛОНЫ ПРОЕКТИРОВАНИЯ / PYTHON / ПРОГРАММИРОВАНИЕ / РАЗРАБОТКА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Могилатов Роман Константинович

Данная научная работа исследует особенности и результаты подхода внедрения зависимостей для разработки программных приложений сети Интернет на базе программного комплекса Dependency Injector.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «ПРИМЕНЕНИЕ ШАБЛОНА ПРОЕКТИРОВАНИЯ ВНЕДРЕНИЯ ЗАВИСИМОСТЕЙ ДЛЯ РАЗРАБОТКИ ИНТЕРНЕТ-ПРИЛОЖЕНИЙ НА ОСНОВЕ ПРОГРАММНОГО КОМПЛЕКСА DEPENDENCY INJECTOR»

16. Dependency injection and inversion of control in Python. [Электронный ресурс]. Режим доступа: https://python-dependency-injector.ets-labs.org/introduction/di_in_python.html/ (дата обращения: 07.06.2021).

17. Dependency injection. [Электронный ресурс]. Режим доступа: https://en.wikipedia.org/wiki/Dependency_injection/ (дата обращения: 07.06.2021).

18. Применение шаблона проектирования внедрения зависимостей для разработки интернет-приложений на основе программного комплекса Dependency Injector // НАУЧНЫЙ ЖУРНАЛ (№ 5 (60) июнь, 2021).

ПРИМЕНЕНИЕ ШАБЛОНА ПРОЕКТИРОВАНИЯ ВНЕДРЕНИЯ

ЗАВИСИМОСТЕЙ ДЛЯ РАЗРАБОТКИ ИНТЕРНЕТ-ПРИЛОЖЕНИЙ НА ОСНОВЕ ПРОГРАММНОГО КОМПЛЕКСА DEPENDENCY INJECTOR Могилатов Р.К.

Могилатов Роман Константинович - ведущий инженер, направление Python, компания СофтСерв, г. Днепр, Украина

Аннотация: данная научная работа исследует особенности и результаты подхода внедрения зависимостей для разработки программных приложений сети Интернет на базе программного комплекса Dependency Injector.

Ключевые слова: внедрение зависимостей, шаблоны проектирования, Python, программирование, разработка программного обеспечения.

Цель исследования

Данная научная работа исследует особенности и результаты подхода внедрения зависимостей для разработки программных приложений сети Интернет на базе программного комплекса Dependency Injector.

Техническое задание

Создать программное приложение для работы в сети интернет на базе программного комплекса Dependency Injector. Для разработки необходимо использовать высокоуровневый язык программирования общего назначения с динамической строгой типизацией и автоматическим управлением памятью Python.

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

Функциональные требования:

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

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

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

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

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

- Для каждого найденного репозитория с программным кодом программное приложение должно отобразить:

- имя репозитория с программным кодом

- имя владельца репозитория с программным кодом

- последний коммит в репозиторий с программным кодом

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

Github Navigator

Search for: Limit.

Dependency Injector 10

Results ......... 10

ft Repository

1 python-dependency-inJeCtor

2 DependencyinjectorBenchmarks

3 Dependencyinjector

1 express-dependency-injector

5 Ultra-Lightweight-Dependency-Injector-Python

Repository owner Lost commit

Я stehet "J Ijacqu

3ee629eb5d7349dS5f41bn9aff8ldd2l90?la0l Merge branch 'release/3.22.01 into master Roman Mogylatov

OOd2b3c7e76935d76f25eeSOf6d1l2ef6ddce131 Merge pull request #14 from ipjohnson/master adding Grace container Stefan Jokul Sigurflarson

bb45d9e3b986D8047190bf72a95fa9a37d8c4o9e Update Checkstyle config to be in sync with the version used by CodeClimate Ijacqu

468856OO3c273dffee23b0S791fbbe5l2a0ebede Incrementing package version from PR Tim Walker

2c30746cta91b4947583416c833b1644a85c759d added some text and todo. Gitrlio De Donato

Рис. 1. Макет пользовательского интерфейса Подготовка окружения для исследования

Перед началом исследования нам необходимо подготовить окружение. Для исследования мы будем использовать программный пакет virtual environment языка программирования Python. Этот пакет создает виртуальное окружение для работы. Создадим виртуальное окружение языка программирования Python: mkdir ghnav-flask-tutorial cd ghnav-flask-tutorial python3 -m venv venv

Активируем виртуальное окружение языка программирования Python: . venv/bin/activate

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

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

Выполним создание структуры проекта в файловой системе соответственно следующей схеме:

■ githubnavigator/ init .py

■ application.py

■ containers.py - views.py

■ venv/ 1-requirements.txt

Переходим к установке Flask и Dependency Injector. Добавим следующие строки в файл requirements.txt: dependency-inj ector flask

Далее установим пакеты из менеджера пакетов PyPI:

pip install -r requirements.txt

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

python -c "import dependency injector; print(dependency_injector._version_)"

python -c "import flask; print(flask._version_)"

При успешной установке интерфейс командной строки покажет следующие строки:

(venv) $ python -c "import dependency_injector;

print(dependency_inj ector._version_)"

3.22.0

(venv) $ python -c "import flask; print(flask._version_)"

1.1.2

Создание макета минимального интернет приложения

Для продолжения исследования нам необходимо создать минимальное интернет приложение. При создании приложения применим принцип внедрения зависимостей с помощью программного комплекса Dependency Injector. Добавим следующие строки в файл views.py:

......Views module.......

def index():

return 'Hello, World!'

Далее добавим контейнер зависимостей. Контейнер зависимостей является основным компонентом при применении принципа инверсии управления. Контейнер будет содержать все компоненты приложения. Добавим первые два компонента. Это Flask приложение и представление index. Добавим следующее в файл containers.py: ......Application containers module.......

from dependency injector import containers fro m dependency ini ector.ext import flask from flask import Flask

from . import views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

index_view = flask.View(views.index) Для продолжения исследования создаем фабрику Flask приложения. Назовем ее create_app(). Она будет создавать контейнер. Контейнер будет использован для создания Flask приложения. Последним шагом настроим маршрутизацию — мы назначим представление index_view из контейнера обрабатывать запросы к корню "/" приложения.

Отредактируем application.py:

......Application module.......

from .containers import ApplicationContainer

def create app():

......Create and return Flask application.......

container = ApplicationContainer()

app = container.app() app.container = container

app.add_url_rule('/', view_func=container.index_view.as_viewO) return app

Интернет приложение готово к запуску.

Выполните в терминале:

export FLASK APP=githubnavigator.application

export FLASK_ENV=development

flask run

Вывод должен выглядеть следующим образом:

* Serving Flask app "githubnavigator.application" (lazy loading)

* Environment: development

* Debug mode: on

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

* Restarting with fsevents reloader

* Debugger is active!

* Debugger PIN: 473-587-859

Откройте браузер и зайдите на http://127.0.0.1:5000/. Ожидаемый результат -интернет страница с текстом «Hello, World!». Подключение каскадных таблиц стилей

Для внедрения в исследование каскадных таблиц стилей будем использовать программный пакет Bootstrap 4. Используем для этого расширение Bootstrap-Flask. Оно поможет нам добавить все необходимые файлы. Добавим bootstrap-flask в requirements.txt: dependency-inj ector flask

bootstrap-flask

и выполним в терминале:

pip install --upgrade -r requirements.txt

Теперь добавим расширение bootstrap-flask в контейнер.

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Отредактируйте containers.py:

......Application containers module.......

from dependency injector import containers fro m dependency щ ector.ext import flask from flask import Flask from flask_bootstrap import Bootstrap

from . import views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

bootstrap = flask.Extension(Bootstrap)

index_view = flask.View(views.index) Давайте инициализируем расширение bootstrap-flask. Нам нужно будет изменить create_app().

Отредактируйте application.py: ......Application module.......

from .containers import ApplicationContainer

def create app():

......Create and return Flask application.......

container = ApplicationContainer()

app = container.app() app.container = container

bootstrap = container.bootstrap() bootstrap.init_app(app)

app.add_url_rule('/', view_func=container.index_view.as_viewO) return app

Теперь нужно добавить шаблоны. Для этого нам понадобится добавить папку templates/ в пакет githubnavigator. Внутри папки с шаблонами добавим два файла:

• base.html — базовый шаблон

• index.html — шаблон основной страницы

Создаем папку templates и два пустых файла внутри base.html и index.html: ./

|-githubnavigator/

| |-templates/

| | |-base.html

| | '-index.html

| |- init .py

| |-application.py

| |-containers.py

| '-views.py

|-venv/

'-requirements.txt

Теперь давайте наполним базовый шаблон. Добавим следующие строки в файл base.html: <!doctype html> <html lang="en"> <head>

{% block head %}

<!-- Required meta tags -->

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-

fit=no">

{% block styles %} <!-- Bootstrap CSS --> {{ bootstrap.load_css() }} {% endblock %}

<title>{% block title %}{% endblock %}</title> {% endblock %}

</head>

<body>

<!-- Your page content --> {% block content %}{% endblock %} {% block scripts %}

<!-- Optional JavaScript --> {{ bootstrap.load_js() }} {% endblock %} </body> </html>

Теперь наполним шаблон основной страницы. Добавим следующие строки в файл index.html:

{% extends "base.html" %}

{% block title %}Github Navigator{% endblock %} {% block content %} <div class="container">

<h1 class="mb-4">Github Navigator</h1> <form>

<div class="form-group form-row"> <div class="col-10">

<label for="search_query" class="col-form-label">

Search for: </label>

<input class="form-control" type="text" id="search query" placeholder="Type something to search on the GitHub" name="query"

value="{{ query if query }}">

</div>

<div class="col"> <label for="search_limit" class="col-form-label">

Limit: </label>

<select class="form-control" id="search_limit" name="limit"> {% for value in Г5, 10, 201 %} <option {% if value == limit %}selected{% endif %}>

{{ value }} </option> {% endfor %} </select> </div> </div> </form>

<p><small>Results found: {{ repositories|length }}</small></p> <table class="table table-striped"> <thead> <tr>

<th>#</th> <th>Repository</th>

<th class="text-nowrap">Repository owner</th> <th class="text-nowrap">Last commit</th> </tr> </thead> <tbody>

{% for repository in repositories %} {{n}}

30

<tr>

<th>{{ loop.index }}</th> <td><a href="{{ repository.url }}">

{{ repository.name }}</a> </td>

<td><a href="{{ repository.owner.url }}"> <img src="{{ repository.owner.avatar url }}" alt=''avatar" height="24" width="24"/></a> <a href="{{ repository.owner.url }}"> {{ repository.owner.login }}</a> </td>

<td><a href="{{ repository.latest commit.url }}"> {{ repository.latest commit.sha }}</a> {{ repository.latest commit.message }} {{ repository.latest_commit.author_name }}

</td> </tr> {% endfor %} </tbody> </table> </div>

{% endblock %}

Последним шагом изменим представление index чтобы оно использовало шаблон index.html. Отредактируем views.py: ......Views module.......

from flask import request, render_template def index():

query = request.args.get('query', 'Dependency Injector') limit = request.args.get('limit', 10, int)

repositories = []

return render template( 'index.html', query=query, limit=limit,

repositories=repositories,

)

Выполним flask run и откроем страницу http://127.0.0.1:5000/. Ожидаемый результат:

Рис. 2. Пользовательский интерфейс после подключения каскадных таблиц стилей

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

Для интеграции с базой данных удаленного веб-сервиса GitHub будем использоваться программный комплекс PyGithub.

Добавим программный комплекс в файл requirements.txt:

dependency-inj ector

flask

bootstrap-flask pygithub

и выполним в терминале:

pip install --upgrade -r requirements.txt

Далее нам необходимо интегрировать Github API клиент в контейнер зависимостей. Для этого нам необходимо будет воспользоваться следующими провайдерами из модуля dependency_injector.providers:

• Провайдер Factory необходим для создания Github клиента.

• Провайдер Configuration необходим для передачи API токена и таймаута Github клиенту.

Отредактируем containers.py: ......Application containers module.......

from dependency injector import containers, providers

fro m dependency ini ector.ext import flask

from flask import Flask

from flask bootstrap import Bootstrap

from github import Github

from . import views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask, __name_)

bootstrap = flask.Extension(Bootstrap)

config = providers.Configuration()

github client = providers.Factory( Github,

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

login or token=config.github.auth token, timeout=config.github.request_timeout,

)

index_view = flask.View(views.index)

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

Теперь добавим файл конфигурации. Будем использовать формат YAML. Создаем файл config.yml в корне проекта: ./

|-githubnavigator/

| |-templates/

| | |-base.html

| | '-index.html

| |- init .py

| |-application.py

| |-containers.py

| '-views.py

|-venv/

|-config.yml

'-requirements.txt

И заполняем его следующими строками: github: request_timeout: 10

Для работы с конфигурационным файлом мы будем использовать программный комплекс PyYAML. Добавим ее в файл зависимостей. Отредактируем requirements.txt: dependency-inj ector flask

bootstrap-flask

pygithub

pyyaml

и установим зависимость:

pip install --upgrade -r requirements.txt

Для передачи API токена мы будем использовать переменную окружения GITHUB_TOKEN.

Далее нам необходимо отредактировать create_app() чтобы сделать 2 действие при старте приложения:

• Загрузить конфигурацию из файла config.yml

• Загрузить API токен из переменной окружения GITHUB_TOKEN Отредактируем файл application.py:

......Application module.......

from .containers import ApplicationContainer

def create app():

......Create and return Flask application.......

container = ApplicationContainer() container.configfrom yaml('configymT)

container.config.github.auth_token.from_env('GITHUB_TOKEN')

app = container.appO app.container = container

bootstrap = container.bootstrapO bootstrap.init_app(app)

app.add_url_rule('/', view_func=container.index_view.as_viewO) return app

Далее нам необходимо создать API токен. Для это необходимо:

• Следовать руководству веб-сервиса GitHub: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token

• Установить токен в переменную окружения: export GITHUB_TOKEN=<your token>

Веб-приложение может работать без токена, но с ограниченной пропускной способностью. Ограничение для неаутентифицированных клиентов: 60 запросов в час. Токен нужен чтобы увеличить эту квоту до 5000 в час. Интеграция Github API клиента завершена. Внедрение программной службы поиска

Следующим этапом исследования является внедрение программной службы поиска SearchService. Данный компонент будет выполнять следующие функции:

• Осуществление поиска репозиториев с программным кодом на удаленном сервере базы данных веб-приложения Github

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

• Преобразовывать формат результата SearchService будет использовать Github API клиент. Создаем пустой файл services.py в пакете githubnavigator:

|-githubnavigator/

| |-templates/

| | |-base.html

| | '-index.html

| |- init .py

| |-application.py

| |-containers.py

| |-services.py

| '-views.py

|-venv/

|-config.yml

'-requirements.txt

и добавляем в него следующие строки:

......Services module.......

from github import Github

from github.Repository import Repository

from github.Commit import Commit

class SearchService:

......Search service performs search on Github.......

def init (self, github client: Github): self._github_client = github_client

def search repositories(self, query, limit):

......Search for repositories and return formatted data.......

repositories = self._github_client.search_repositories( query=query, **{'in': 'name'},

)

return [

self. format repo(repository) for repository in repositories[:limit]

]

def format repo(self, repository: Repository): commits = repository.get_commits() return {

'url': repository.html url, 'name': repository.name, 'owner': {

'login': repository.owner.login, 'url': repository.owner.html url, 'avatar_url': repository.owner.avatar_url,

},

'latest_commit': self._format_commit(commits[0]) if commits else {},

}

def _format_commit(self, commit: Commit): return {

'sha': commit.sha, 'url': commit.html url, 'message': commit.commit.message, 'author_name': commit.commit.author.name,

}

Теперь добавляем SearchService в контейнер зависимостей Dependency Injector. Отредактируем файл containers.py: ......Application containers module.......

from dependency injector import containers, providers

fro m dependency ini ector.ext import flask

from flask import Flask

from flask bootstrap import Bootstrap

from github import Github

from . import services, views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

bootstrap = flask.Extension(Bootstrap)

config = providers.Configuration()

github_client = providers.Factory(

Github,

login or token=config.github.auth token, timeout=config.github.request_timeout,

)

search service = providers.Factory( services.SearchService, github_client=github_client,

)

index_view = flask.View(views.index)

Поисковая служба внедрена в контейнер зависимостей Dependency Injector. Переходим к запуску поисковой службы. Выполним внедрение зависимости SearchService в представление index. Отредактируем файл views.py:

......Views module.......

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

from flask import request, render_template

from .services import SearchService

def index(search service: SearchService):

query = request.args.get('query', 'Dependency Injector') limit = request.args.get('limit', 10, int)

repositories = search_service.search_repositories(query, limit)

return render template( 'index.html', query=query, limit=limit,

repositories=repositories,

)

Теперь изменим контейнер чтобы внедрить зависимость SearchService в представление index при его вызове. Отредактируем файл containers.py: ......Application containers module.......

from dependency injector import containers, providers

fro m dependency ini ector.ext import flask

from flask import Flask

from flask bootstrap import Bootstrap

from github import Github

from . import services, views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

bootstrap = flask.Extension(Bootstrap)

config = providers.ConfigurationO

github client = providers.Factory( Github,

login or token=config.github.auth token, timeout=config.github.request_timeout,

)

search service = providers.Factory( services.SearchService, github_client=github_client,

)

index view = flask.View( views.index,

search_service=search_service,

)

Выполним команду flask run и откроем http://127.0.0.1:5000/ для проверки результатов исследования.

Github Navigator

Search lor: Limit:

Dependency Injector 10 v

Results found; 10

# Repository

1 python-dependency-injector

2 DependencylnjectorBenchmarks

3 Dependencylnjector

4 express-dependency-injector

Repository owner Last commit

Ijacqu

Зееб29eb5d7349d55f41 Ы19aff81 dd219071a01 Merge branch release/3 22.0' into master Roman Mogylatov

00d2b3c7e76935d76f25ee50f6d1f2ef6ddce13l Merge pull request #14 from ipjohnson/master adding Grace container Stefan Jdkull Sigurftarson

bb45d9e3b98608047l90bf72a95fa9a37d8c4e9e Update Checkstyle config to be in sync with the version used by CodeClimate Ijacqu

468856003c273dffce23b86791fbbe512a8ebede Incrementing package version from PR Tim Walker

5 Ultra-Lightweight-Dependency-Injector-Python

-iggio

2c30746c1a91b4947583416c833b1644a85c759d added some text and todo. Giulio De Donato

Рис. 3. Пользовательский интерфейс завершенного исследования Рефакторинг конфигурационных значений

Исследуемое представление index содержит два жестко-определенных значения:

• Поисковый запрос по умолчанию

• Лимит количества результатов

Выполним рефакторинг для улучшения структуры приложения и устранения этих недостатков. Перенесем указанные значения в конфигурацию. Отредактируем файл views.py: ......Views module.......

from flask import request, render_template

from .services import SearchService

def index(

search service: SearchService, default query: str, default_limit: int,

):

query = request.args.get('query', default query) limit = request.args.get('limit', default_limit, int)

repositories = search_service.search_repositories(query, limit)

return render template( 'index.html', query=query, limit=limit,

repositories=repositories,

)

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

Отредактируем файл containers.py: ......Application containers module.......

from dependency injector import containers, providers

fro m dependency ini ector.ext import flask

from flask import Flask

from flask bootstrap import Bootstrap

from github import Github

from . import services, views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

bootstrap = flask.Extension(Bootstrap)

config = providers.Configuration()

github client = providers.Factory( Github,

login or token=config.github.auth token, timeout=config.github.request_timeout,

)

search service = providers.Factory( services.SearchService, github_client=github_client,

)

index_view = flask.View(

views.index,

search service=search service,

default query=config.search.default query,

default_limit=config.search.default_limit,

)

Обновим конфигурационный файл. Отредактируем файл config.yml: github: request_timeout: 10 search:

default query: "Dependency Injector" default_limit: 10

Рефакторинг закончен. Конфигурационные значения передаются методом внедрения зависимостей.

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

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

Будем использовать программные пакеты pytest и coverage для запуска процесса автоматизированного тестирования и измерения процента покрытия. Отредактируем файл requirements.txt: dependency-inj ector flask

bootstrap-flask

pygithub

pyyaml

pytest-flask

pytest-cov

и установим новые пакеты: pip install -r requirements.txt Создаем файл tests.py в пакете githubnavigator: ./

|-githubnavigator/

| |-templates/

| | |-base.html

| | '-index.html

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

| |- init .py

| |-application.py

| |-containers.py

| |-services.py

| |-tests.py

| '-views.py

|-venv/

|-config.yml

'-requirements.txt

и добавляем в него следующие строки: ......Tests module.......

from unittest import mock

import pytest

from github import Github from flask import url_for

from .application import create_app

@pytest.fixture def app():

return create_app()

def test index(client, app): github client mock = mock.Mock(spec=Github) github client mock.search_repositories.return_value = [ mock.Mock(

html url='repo1-url', name= 'repol -name ', owner=mock.Mock( login='owner1-login', html url='owner1-url', avatar_url='owner1-avatar-url',

),

get_commits=mock.Mock(return_value=[mock.Mock()]),

),

mock.Mock(

html url='repo2-url', name='repo2-name', owner=mock.Mock( login='owner2-login', html url='owner2-url', avatar_url='owner2-avatar-url',

),

get_commits=mock.Mock(return_value=[mock.Mock()]),

]

with app.container.github client.override(github_client_mock): response = client.get(url_for('index'))

assert response.status code == 200 assert bResults found: 2' in response.data

assert b'repol-url' in response.data assert b'repol-name' in response.data assert b'ownerl-login' in response.data assert b'ownerl-url' in response.data assert b'ownerl-avatar-url' in response.data

assert b'repo2-url' in response.data assert b'repo2-name' in response.data assert b'owner2-login' in response.data assert b'owner2-url' in response.data assert b'owner2-avatar-url' in response.data

def test index no results(client, app): github client mock = mock.Mock(spec=Github) github_client_mock.search_repositories.return_value = []

with app.container.github_client.override(github_client_mock) :

40

response = client.get(url_for('index'))

assert response.status code == 200 assert bResults found: 0' in response.data Запускаем тестирование и проверяем покрытие: py.test githubnavigator/tests.py --cov=githubnavigator Результат:

platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 plugins: flask-1.0.0, cov-2.10.0 collected 2 items

githubnavigator/tests.py .. [100%]

----------coverage: platform darwin, python 3.8.3-final-0-----------

Name Stmts Miss Cover

githubnavigator/ init .py 0 0 100% githubnavigator/application.py 11 0 100% githubnavigator/containers.py 13 0 100% githubnavigator/services.py 14 0 100% githubnavigator/tests.py 32 0 100% githubnavigator/views.py 7 0 100%

TOTAL 77 0 100%

Обратите внимание на замену githubclient моком с помощью метода .override(). Таким образом можно переопределить возвращаемое значения любого провайдера. Заключение

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

Для реализации метода внедрения зависимостей мы использовали программный комплекс Dependency Injector.

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

Код исследуемого контейнера зависимостей на базе программного пакета Dependency Injector:

......Application containers module.......

from dependency injector import containers, providers

fro m dependency щ ector.ext import flask

from flask import Flask

from flask bootstrap import Bootstrap

from github import Github

from . import services, views

class ApplicationContainer(containers.DeclarativeContainer): ......Application container.......

app = flask.Application(Flask,_name_)

bootstrap = flask.Extension(Bootstrap)

config = providers.Configuration()

github client = providers.Factory( Github,

login or token=config.github.auth token, timeout=config.github.request_timeout,

)

search service = providers.Factory( services.SearchService, github_client=github_client,

)

index view = flask.View( views.index,

search service=search service,

default query=config.search.default query,

default_limit=config.search.default_limit,

)

Список литературы

19. Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, Erich Gamma (Foreword) // Addison-Wesley Professional; 1st edition (June 28, 1999).

20. Patterns of Enterprise Application Architecture by Martin Fowler. Implementation Patterns by Kent Beck // Addison-Wesley Professional; 1st edition (October 23, 2007).

21. The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt, David Thomas // Addison-Wesley Professional; 1st edition (October 1, 1999).

22. Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin // Pearson; 1st edition (August 1, 2008).

23. Building Microservices: Designing Fine-Grained Systems by Sam Newman // O'Reilly Media; 1st edition (February 2, 2015).

24. Design Patterns: Elements of Reusable Object-Oriented Software by GoF - Gang of Four - Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides // Addison-Wesley Professional; 1st edition (November 10, 1994).

25. Refactoring: Improving the Design of Existing Code (2nd Edition) by Martin Fowler // Addison-Wesley Professional; 2nd edition (November 30, 2018).

26. Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans // Addison-Wesley Professional; 1st edition (August 20, 2003).

27. The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition) by Brooks Jr., Frederick P. // Addison-Wesley Professional; Anniversary edition (August 2, 1995).

28. The Innovation Algorithm: TRIZ, systematic innovation and technical creativity (1st Edition) by Genrich Altshuller. // Technical Innovation Ctr; 1st edition (March 1, 1999).

29. Software Estimation: Demystifying the Black Art by Steve McConnell. // Microsoft Press; 1st edition (March 1, 2006).

30. Inversion of Control Containers and the Dependency Injection pattern. [Электронный ресурс]. Режим доступа:https://martinfowler.com/articles/injection.html/

31. Dependency Injector (Documentation). [Электронный ресурс]. Режим доступа: https://python-dependency-injector.ets-labs.org/ (дата обращения: 24.05.2021).

32. Dependency Injector (GitHub). [Электронный ресурс]. Режим доступа:https://github.com/ets-labs/python-dependency-injector/ (дата обращения: 24.05.2021).

33. Dependency Injector (Python Package Index). [Электронный ресурс]. Режим доступа:https://pypi.org/project/dependency-injector/ (дата обращения: 24.05.2021).

34. Dependency injection and inversion of control in Python. [Электронный ресурс]. Режим доступа: https://python-dependency-inj ector. ets-labs.org/introduction/di_in_python.html/ (дата обращения: 24.05.2021).

35. Dependency injection. [Электронный ресурс]. Режим доступа: https://en.wikipedia.org/wiki/Dependency_injection/ (дата обращения: 24.05.2021).

ПРИМЕНЕНИЕ ТЕХНОЛОГИИ SWR В ПРИЛОЖЕНИИ NEXT.JS

1 2 Князев И.В. , Коптева А.В.

'Князев Илья Вадимович - разработчик программного обеспечения, June Homes, г. Белгород;

2Коптева Анна Витальевна - разработчик программного обеспечения, MTC Digital, г. Краснодар

Аннотация: в статье анализируется работа технологии SWR в веб-приложениях с использованием технологии NEXT.JS, преимущества этой технологии, структура кода, использование и практические примеры. Ключевые слова: swr, reactjs, nextjs, javascript.

Хранение данных и работа с состоянием в Next.JS приложении всегда являлись одной из самых важных архитектурных проблем, решение которой влияло на работу всего приложения. С каждым годом становится очевиднее, что проектировать большое веб-приложение под Redux/Flux паттерн является чрезмерно сложным, трудозатратным и менее эффективным.

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

Вступление.

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

Что же означает аббревиатура SWR? Данное название происходит от stale-while-revalidate, основная идея которого заключается в кэшировании данных, что делает его все более популярным в разработке веб-приложений. Эта стратегия инвалидации HTTP-кеша была популяризирована протоколом HTTP RFC 5861. Его главное преимущество в том, что он загружает закэшированные данные сразу же, и обновляет их "на лету", и только затем отправляет fetch запрос (повторная валидация) и получает актуальные данные. Данный паттерн позволяет обрабатывать уже обновленный контент, что является отличным компромиссом между UX (пользовательским опытом) и эффективностью веб-приложения.

Какие основные преимущества SWR?

• Легковесный: быстрая, легкая и многоразовая выборка данных

• Встроенный кеш и дедупликация запросов

• Не зависит от протокола данных

• Ориентирован на «JAM» стэк (JavaScript, API, Markup)

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

• Не зависит от серверной части, т.е. не требует, чтобы фронтэнд часть вашего приложения была основана на таких технологиях и языках программирования как rails, node.js, python или каких-либо еще. Он написан на node.js.

• Имеет строгую типизацию с использованием TypeScript

• Легко интегрируется в React и React Native приложения

i Надоели баннеры? Вы всегда можете отключить рекламу.