Артем Лещев / IT – Telegram
Артем Лещев / IT
64 subscribers
15 photos
2 videos
47 links
Авторский IT-блог на разные темы. Тут много чего.

@artem_leshchev — аффтор, ведущий системный аналитик в ВТБ.
Download Telegram
Методы REST. Для выполнения CRUD-операций REST предполагает использование 5 методов: GET, POST, PUT, PATCH, DELETE.

Идемпотентное поведение имеют: GET, PUT, DELETE.
PATCH же может быть идемпотентным, а может и нет. Теоретический пример: если запрос увеличивает атрибут на единицу при каждом вызове, то PATCH перестает быть идемпотентным. Описано на стеке.

Create:
POST в стандартных случаях (создается дочерний ресурс).
PUT — в случаях, когда идет запрос на обновление ресурса, которого не существует.

Read:
GET — в стандартных случаях, когда требуется отгрузить данные с сервера на клиент, а не изменить их.
POST — в случае, когда GET-запрос содержит большое количество query-параметров (классический пример: фильтрованный список чего-либо), то они могут ухудшать читабельность запроса, и, гипотетически вызывать проблему ограничения допустимой длины URL в браузерах и веб-серверах.

Update:
PUT — в случае полного обновления данных, т.е. замены всех значений в каждом поле у записи.
PATCH — в случае частичного изменения данных, т.е. обновления нескольких полей в БД.

Delete:
DELETE — в случаях явного удаления записи из БД.
PATCH — в случаях архивации, т.е. проставления таймштампа в поля deleted_at / archived_at базы данных.

#API
Нормализация это метод проектирования базы данных, направленный на устранение избыточности данных посредством декомпозиции таблиц.

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

Всего существует 5 основных нормальных форм (1НФ5НФ), 4 дополнительных:
(1) нулевая, т.е. ненормализованная (не отвечающая реляционным принципам как таковым);
(2) Бойса-Кодда (создает "усиление" 3НФ для тех случаев, когда ПК составной. Актуально, если таблица имеет столбцы с ключами-кандидатами).
Если ПК простой, то таблицы автоматически состоят в НФБК 3НФ);
(3) доменно-ключевая (идет после 5НФ);
(4) шестая (последняя).

На реальных проектах дальше 3НФ/НФБК обычно не декомпозируют. Они уже устраняют достаточно аномалий, а дальнейшее приведение БД к 4НФ будет негативно сказываться на производительности. Тем не менее, наверное, в любой предметной области есть сущности, которые логично декомпозировать до 4НФ, просто в этом нужды нет. Реальную же необходимость 5НФ, ДКНФ и 6НФ даже сложно представить, поэтому они представляют лишь теоретический интерес.

0НФ таблица не относится к реляционной модели данных, потому что не отвечает требованиям 1НФ.

Пример: таблица в Excel.
Каждая строка имеет номер, а каждый столбец упорядочен по английскому алфавиту (A, B, C...).
В реляционной же модели записи не имеют номеров, а значит хранятся в неотсортированном виде; очередность полей тоже роли не играет. Сортировка записей задается принудительно оператором ORDER BY в DML-командах, а значит не затрагивает структуру БД.

Помимо Excel, к 0НФ можно отнести и NoSQL, а также просто таблицы где данные банально намешены в кучу...

🟢 1НФ в центре внимания соблюдение реляционных принципов:

1️⃣ каждая запись уникальна (нет дубликатов);
2️⃣ каждое поле содержит атомарное (не составное) значение;

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

3️⃣ в каждом поле данные только одного типа;
4️⃣ отсутствие массивов (любых, даже хранение JSON уже нарушение классической реляционности, хотя сейчас и есть json-типы для полей).

#SQL
2НФ — неключевые поля должны зависеть как минимум от полного первичного ключа. То есть, допускается транзитивная зависимость.
3НФ — неключевые поля должны зависеть только от полного первичного ключа. То есть, НЕ допускается транзитивная зависимость.

🟢 2НФ в центре внимания корректное использование первичного ключа:

1️⃣ таблица состоит в 1НФ;
2️⃣ есть ПК;
3️⃣ каждое неключевое поле обязательно должно зависеть от всех полей ПК, а также опционально может зависеть от других полей.

Одна и та же таблица может как состоять в 2НФ, так и нет, в зависимости от бизнес-процесса. Пример из Википедии как раз об этом. В случае если в рассматриваемой компании наличие компьютера будет зависить И от филиала, И от должности, то таблица уже во 2НФ.

Функциональная зависимость имеет правило: если в двух строках таблицы совпадают значения столбца X (например, есть две строки со значением "Программист" в таблице выше), то обязаны совпадать и значения столбца Y (действительно, у обоих "Наличие компьютера" = Есть).

Чтобы протестировать зависимость полей от всего составного ключа, надо задать вопрос:
Могу ли я определить {Неключевое_поле}, зная только {Часть_составного_ключа}?
Если ответ "да" — то это не 2НФ. Что же делать?

Если ключ составной, то его можно:
(а) ликвидировать, введя простой суррогатный ключ типа integer;
(б) декомпозировать таблицу на несколько (чаще всего 3, с таблицей-связкой). Тем самым, составной ПК поделится на простые.

🟢 3НФ в центре внимания неключевые поля:

1️⃣ таблица состоит во 2НФ;
2️⃣ отсутствует транзитивная зависимость (неключевые столбцы зависят от значений других неключевых столбцов).

Классический пример, когда в таблице сотрудников находится поле с номером телефона отдела, которое связано напрямую с полем "Название отдела", и уже через него связано сотрудником (транзитивно).

Таким образом, приведение к 3НФ осуществляется через декомпозицию: необходимо поле "Номер телефона" вынести в таблицу отделов.

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

‼️ Если по итогу приведения к 3НФ у нас образуется простой ПК, то таблица автоматически переходит в форму Бойса-Кодда. Если же ПК составной или есть ключи-кандидаты, то требуется приведение к НФБК.

#SQL
👨‍💻🐍 Как запустить код без IDE?

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

На примере языка Python и ОС Windows алгоритм следующий:

(1) Открыть командную строку в директории нахождения файла.

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

Либо из текущей директории переходить вверх-вниз по каталогу, пока мы не попадем в нужная папку. Для этого используем команду change directory:

(а) подняться на каталог выше: cd ..
(б) спуститься на каталог ниже: cd {catalogName}
(в) узнать название нужного каталога можно получив список содержимого текущей директории: dir

2) В нужном каталоге выполнить команду запуска файла с кодом: python {fileName}.py

#Python #Программирование

Артем Лещев
Диаграмма последовательности (Sequence) уточняет процессы, представленные на диаграммах вариантов использования (Use-case), другими словами — визуализирует их более подробно.

Sequence‑диаграмма состоит из следующих элементов:

🟢 Объекты. Это сущности, которые взаимодействуют друг с другом. Самые частоиспользуемые типы объектов это:

(1) participant. Объект, который что-то выполгняет в системе
(2) actor. Внешняя сущность, взаимодействующая с системой (часто живой человек).
(3) database. База данных.
(4) queue. Брокер сообщений.

Обычно, их достаточно для визуализации последовательности действий. Реже используют следующие типы:

(5) boundary. Границы системы для внешнего пользователя. Часто - UI для пользователя.
(6) control. Контроллер, выполняющий операции. Программный компонент, модуль, обработчик.
(7) entity. Сущность для хранения информации, часто может быть представлена таблицей/полем в БД.
(8) collections. Коллекции. Группа объектов (массив, список и т.д.) объединенных общими атрибутами. Используют для повышения абстракции.

🟢 Линии жизни. Вертикальные пунктирные линии, отображающие течение времени.

🟢 Фокус управления. Вертикальные прямоугольники, расположенны ена линии жизни и отображающие активность конкретной сущности в конкретный момент времени.

🟢 Сообщения. Стрелки, отвечающие за обмен информацией между объектами. При получении сообщения объект-получатель активируется, а значит у него активируется фокус управления.

Сообщения бывают разные:

(1) Прямая линия с закрашенной стрелкой. Синхронный вызов операции.
(2) Прямая линия с острой стрелкой. Асинхронный вызов операции.
(3) Пунктирная линия с острой стрелкой. Ответное сообщение.

Используются редко:

(4) Потерянное сообщение. Сообщение не имеет адресата. Нет события передачи и не события приема.
(5) Найденное сообщение. Сообщение не имеет инициатора. Нет события передачи, есть только событие приема.

🟢 Операторы управления.
Чаще всего используют alt и opt. Редко loop и par.

(1) alt. Моделирование условных операторов в коде, который позволяет выбрать различные ветки выполнения в зависимости от условий.
(2) opt. Моделирование ветвей (развилок) выполнения.

Может быть одно или несколько сообщений.

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

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

(3) par. Моделирование параллельных процессов. Важное отличие от Opt — может быть одно или несколько ветвей выполнения. Все подобласти начинают выполняться параллельно. Это важно.

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

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

(4) loop. Моделирование циклов.

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

Используются редко:

(5) break. Прерывание цикла. Используется для выхода из цикла при выполнении определенного условия.

(6) assert. Утверждение. Служит для проверки условия и выдачи ошибки, если условие не выполняется.

(7) critical. Критическая секция, которая может быть выполнена только одним потоком одновременно.

#UML #Sequence

Артем Лещев
Написал код, для создания диаграммы микросервиса инцидентов из статьи на Хабре.

@startuml
noscript GET Алгоритм /pl-incident-alert/v1/incidents
header 1
hide footbox
center footer Сделано для демонстрации
autonumber "<b>(0)"
skinparam sequence {
MaxMessageSize 200
ParticipantPadding 30
MessageAlign center
}

participant "МП МТСБ" as mp order 10
participant "pl-incident-alert" as pl order 20
database "DB-pl-incident-alert" as db order 30

mp -> pl : Get incidents
pl -> db : Request
pl <-- db : Response

alt #b3ffb3 successful case
pl -> mp : HTTPS/ 1.1 200 OK
else #ffb3d9 some kind of failure
pl -> mp : HTTPS/ 1.1 204 No content
end
@enduml

#UML

Артем Лещев
👍1🔥1👏1
С коллегой зашел разговор о природе представлений (view).

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

Представления делятся на 2 вида:

1️⃣ Обычные. CREATE VIEW.
Не хранит данные, соответственно, при каждом новом вызове данные будут актуальные.
В базе сохраняется только сам запрос, а не таблица.

2️⃣ Материализованные. CREATE MATERIALIZED VIEW.
В базе сохраняются результаты запроса, а не только его представление.
При вызове отобразит данные на момент последнего обновления (команда REFRESH).
Выборка из материализованннного представления происходит намного быстрее, чем из обычного.

В документации PostgreSQL есть такой пассаж:

Активное использование представлений — это ключевой аспект хорошего проектирования баз данных SQL.

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

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

В книге "Оптимизация запросов в PostgreSQL" авторы Домбровская, Новиков и Бейликова называют представления "самым противоречивым объектом".

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

Соответственно, создание эффективного и полезного представления превращается в, я бы сказал, тонкое искусство.

‼️Лучшей производительности представления не дают, зато легко могут ее забрать, что особенно ярко проявляется, например, когда некоторые поля в представлении являются результатами преобразований (а в этом случае индексы не выполняются!).

Так, например, если в представлении есть преобразования вроде:

SELECT COALESCE(actual_departure, schedule_departure)::date AS departure_date

то запрос с фильтрацией по этому полю:

SELECT field_name
FROM view_name
WHERE departure_date = '2020-08-01'

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

#SQL #PostgreSQL

Артем Лещев
Работая в Postman с веб-сокетом (подпротокол WAMP, если бы точнее), столкнулся с проблемой. Не удавалось установить соединение.

🔴 Появлялась ошибка:

Could not connect to wss://{my-domen}/
Error: Unexpected server response: 400
Request Method: GET
Status Code: 400 This server only speaks WebSocket subprotocols wamp.2.cbor.batched, wamp.2.cbor, wamp.2.msgpack.batched, wamp.2.msgpack, wamp.2.ubjson.batched, wamp.2.ubjson, wamp.2.json.batched, wamp.2.json


🟢 Для решения нужно было в заголовках запроса передать:

Sec-WebSocket-Protocol: {список протоколов, указанных в ошибке}

Sec-WebSocket-Protocol это заголовок запроса и ответа, используется в веб-сокетном рукопожатии.

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

✏️ MDN (Mozilla Developer Network, сборник документации по вебу) советует думать о подпротоколах как о структуре, а-ля XML или Doctype.

Принцип работы следующий:

1️⃣ В заголовке запроса, отправляемого с клиента, перечисляется список подпротоколов.
2️⃣ Сервер выбирает один для использования. Выбор подпротокола записывается в аналогичный заголовок ответа.

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

Если сервер не обрабатывает ни один из переданных подпротоколов, то он вообще не отправляет заголовок ответа Sec-WebSocket-Protocol.

Я же вначале открыл DevTools и скопипастил заголовки запроса в Bulk edit Postman. Появилась ошибка:

Error: Invalid Sec-WebSocket-Accept header

Как я её только не пытался решить! На Гитхабе нашел этот ответ.

Надо было удалить заголовки Sec-Websocket-Key и все прочие, которые не требуются. Ну, а исходя из первоначлаьной ошибки, требовалось только перечислить подпротоколы.

#API #WebSockets

Артем Лещев
🐍 Вспоминаю основы Python. В этом посте — сборка различной базовой информации.

🟢 Работа с языком.

(1) Документация к языку.
(2) Cтандартная библиотека Python.
(3) Туториал.
(4) Сводка по синтаксису.

🟢 Типизация.

Python имеет динамическую сильную неявную типизацию.

(1) Динамическая. Одной и той же переменной в коде могут быть присвоены различные типы данных.
(2) Сильная. Не позволяет смешивать в выражениях различные типы и автоматически их преобразовывать.
(3) Неявная. Не требуется явно указывать тип переменной.

🟢 Менеджер пакетов pip.

(1) pip  — это стандартный инструмент для установки пакетов из системы PyPI (Python Package Index). PyPI — репозиторий с каталогом дистрибутивов.
(2) Conda. Для импорта научного софта обычно используют не pip, а conda — отдельную систему управления пакетами, зависимостями и окружениями.
(3) Документация по работе с pip.

🟢 Пакеты, библиотеки, модули.

Пакет (package) — структурированный каталог модулей.
Бывает двух видов:

(1) Distribution package. Софт, устанавливаемый с помощью pip, а именно командой pip install pkg. Второй пример: когда мы управляем зависимостями: dependencies = ["pkg"] в pyproject.toml.

(2) import package. Импортируемый модуль Python (import pkg или from pkg import func). Может иметь подмодули, например numpy.linalg.

Модуль — просто файл с расширением .py, иногда это могут быть файлы на внешних языках. Библиотеки Python состоят из модулей, где уже находятся классы, а в них - функции. Модули могут импортировать другие модули.

Операторы обработки модулей (цитата из книги Марка Лутца "Изучаем Python") следующие:

Модули обрабатываются с помощью двух операторов и одной важной функции.
(1) import. Позволяет клиенту (импортеру) извлечь модуль как единое целое.
(2) from. Позволяет клиентам извлекать отдельные имена из модуля.
(3) imp.reload. Предоставляет способ перезагрузки кода модуля, не останавливая Python.
🟢 Виртуальная машина Python (PVM).

Интерпретатор Python выполняет скрипт поэтапно.

(1) Написаный код компилируется в байт-код (файлы с расширением .pyc в папке pycache).
(2) Отправка байт-кода в виртуальную машину.
(3) Компиляция C-инструкций в машинный код для процессора компьютера.

Виртуальной машиной чаще всего является CPython, написанный на C, но есть и другие узкоспецифичные реализации, например, Jython (для интеграции с Java).

CPython-интерпретатор принимает на вход байт-код и пропускает его через гигантские for-цикл и условный оператор switch в файле cevel.c (свыше 5000 строк исходного кода). По итогу, C-код компилируется в машинный код, который уже отдается процессору компьютера.

Другие реализации PVM, например PyPy, имеют Just-In-Time (JIT) компиляцию, т.е. они переводят Python-инструкции в машинный код "на лету".

🟢 Установка Python. Виртуальные окружения.

Нужная версия Python для нужной разрядности ОС скачивается с официального сайта python.org. Рекомендуется скачивать версию с Maintenance status = security.

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

Под каждый проект лучше заводить свое виртуальное окружение и туда, консольной командой pip install, устаналивать сторонние пакеты.

Виртуальное окружение (venv) — это изолированная среда для проекта. Документация. Нельзя все пакеты устаналивать в корневую Python-папку: будет каша и не нужные зависимости, которые усложнят разработку и поддержку проекта. Виртуальное окружение решает эти проблемы.

Статья по созданию venv.

#Python #Программирование

Артем Лещев
👨‍💻 Что такое хэширование пароля?

Участвую в конкурсе «Продолжи мысль» от @systems_education.

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

Шифрование и хэширование — разные методы защиты информации. Первый подразумевает наличие ключа, которым можно расшифровать данные. Второй — необратимый процесс.

Необратимый, потому что алгоритма дехэширования нет. Символы пароля и хэша не маппятся друг с другом один-в-один. Чтобы "дехэшировать" нужно банально подобрать хэш, но число вариантов для перебора будет огромно. Так называемые "радужные таблицы" позволяют его подбирать более оптимальным способом, из-за чего выясняется, что некоторые алгоритмы (например, MD5 и SHA-1) не в состоянии надежно хэшировать данные, а потому, их не рекомендуют использовать для защиты паролей. Алгоритмы отличаются друг от друга математическими операциями, которые не должны порождать коллизий, то есть не генерировать одинаковый хэш для разных входных данных.

🧂Чтобы обеспечить дополнительную защиту, хэш-функции усложняют пароль, добавляя так называемую "соль" (salt), т.е. сторонние символы. Важно понимать, что соль касается только хэширования, и нужна на случай взлома базы данных. Поэтому сами пароли должны быть длинной разносимвольной тарабарщиной, а не условный qwerty.

✏️ В языках программирования присутствуют как встроенные хэш-функции, так и можно использовать сторонние модули. Один из самых популярных модулей — bcrypt, основанный на алгоритме Blowfish.

🐍 Набросал фиддл на Python где:

(1) импортируется модуль bcrypt;
(2) создается пароль, преобразованный в байты;
(3) генерируется соль с фактором стоимости (cost factor) в 12 кругов итераций (для большей устойчивости к атакам);
(4) создается хэш пароля функцией hashpw();
(5) проверяется, что поданный на вход пароль соответствует тому, который был хэширован.

Выполнил по документации bcrypt-модуля.

Стандартная библиотека Python также содержит модуль для хэширования, называющийся hashlib.

🟢 Хэширование средствами базы данных. В PostgreSQL есть отдельный модуль pgcrypto, который предоставляет широкие возможности для генерации хэшей разными способами.

Помимо этого, в PostgreSQL просто есть функции задействующие хэширование разными алгоритмами (допустим, тот же SHA), описанные в документации.

#продолжи_мысль_SE

#Программирование #Python #SQL

Артем Лещев
1
Пару дней назад пообщался с одним знакомым коллегой — проектным менеджером и компьютерным мастером в одном лице. 💪 Во как!

Он поинтересовался моим мнением относительно некоторых вещей. Вот мои соображения:

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

🟢 (2) Я убежден, что лучшие друзья менеджера — это разработчики. Только они знают как на самом деле работает фича. Их консультации самые ценные.

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

🟢 (4) Уметь программировать — самый недооцененный навык для любого ИТ-специалиста. Даже менеджера и аналитика. Но тем не менее, уметь программировать != быть разработчиком.

🟢 (5) Проблемы ИТ-рынка:

📚👨‍💻 (а) Нехватка квалифицированных кадров. Особенно удручающая ситуация с разработчиками — для них курсы абсолютно бесполезны. Джун, прочитавший учебник, знает сильно больше джуна прошедшего курс.

🩼 (б) Большинство импортозамещенных ИТ-решений создавались наспех, а потому находятся в весьма сыром виде. Нестабильность работы, баги, косячный UX/UI дизайн, ограниченный функционал и множество костылей и техдолгов. Все это будет причесываться и доводиться до ума еще с десяток лет минимум.

#Мысли #Менеджмент

Артем Лещев
👍1
Некоторое время назад имел диалог на тему бизнес-анализа.

Зафиксирую определения самых частоупотребимых терминов:

🟢 Бизнес-аналитикаколичественное исследование бизнеса: сбор, обработка и визуализация метрик для принятия решений стейкхолдерами. Реализуется с помощью BI-инструментов.

🟢 Бизнес-анализкачественное исследование бизнеса: изучение бизнес-процессов компании и требований стейкхолдеров для улучшения количественных показателей.

🟢 Бизнес-правило — это конкретное проверяемое условие, накладывающее ограничение на бизнес-процесс и принятие решения. Замечу, что имеет собственный символ в BPMN.

🟢 Процесс — совокупность повторяющихся действий (работ, функций, операций, задач), в результате создающих ценность для кого-либо, чего-либо.

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

🔸 Функциональное требование — описание действий/функций системы.
🔸 Нефункциональное требование — описание характеристик системы, а также ограничений, которые она должна соблюдать.
Примеры: доступность, ремонтопригодность, безопасность, масштабируемость, удобство использование, соответствие законодательству...

И еще 🙂. Нет, коллега, наличие англоязычной версии сервиса — это как раз-то НФТ, а не ФТ, и называется "локализация".

🟢 Как работать с требованиями?

🔸 SMART

Требования должны быть:
— конкретны;
— измеримы в плане ожидаемого результата;
— достижимы;
— релевантны бизнес-целям;
— ограничены по времени.
🔸 INVEST
Пользовательские истории должны быть:
— независимы друг от друга;
— обсуждаемы в деталях;
— ценными для пользователей;
— поддающимися оценке;
— маленькими, атомарными;
— поддающимися тестированию.
🔸 MoSCoW
Приоритезировать требования надо разбив их 4 группы:
— Must have;
— Should have;
— Could have;
— Won't have.

#Требования

Артем Лещев
🔥1
Наверное, это абсолютный рекорд. Павел Дуров ищет Андроид-рвзработчика, которому готов платить 1 миллион долларов в год.

6,5 миллионов рублей в месяц.

В США айтишники получают в среднем 80-100 тысяч в год. Естественно, зависит от стека и квалификации. А тут - сразу в 10 раз больше.

Тестовое задание - реализовать на Android анимацию, которую на iOS внедрили полгода назад.
🔥1
Forwarded from Pavel Durov (Paul Du Rove)
👨‍💻 Telegram’s looking for an Android dev — who’ll earn $1M / year after tax. 🧻

🥇 The only way in is to win our coding contest that ends on July 11. The task? Implement the animation from this mockup in our open-source Android app. 🤖 https://news.1rj.ru/str/contest/420
Please open Telegram to view this post
VIEW IN TELEGRAM
🐍 Создание виртуального окружения

В крупных коммерческих проектах часто используют не обычные pip и venv, а современные инструменты, например, poetry или uv. Они сильно упрощают (=ускоряют) работу с пакетами, окружениями и зависимостями.

Тем не менее, не повредит знать как стандартным способом создать виртуальное окружение:

1⃣ Начинаем, естественно, с создания папки проекта.

2⃣ Открыть директорию проектной папки в консоли. Выполнить команду:
python -m venv {venv_name}

3⃣
Теперь нужно активировать виртуальное окружение:
{venv_name}\Scripts\activate
В случае успеха выведет в консоль:
({venv_name}) {Path_to_project}
Например:
(my_project) D:\python_projects\my_project

4⃣ Уд
аляется venv следующей командой:
rmdir {venv_name} /s /q

5⃣ Ес
ть еще интересная команда pip freeze, которая отобразит список всех установленных пакетов в виртуальной среде.

6⃣ pip uninstall {package_name}
удалит и
з директории ненужный пакет.

🐍 📊 А вот аналитический код я сейчас пишу в облачной Anaconda, в Jupyter Notebook.

Там окружение создается так:

7⃣ Создать папку для проекта и открыть Linux-терминал:
File >
New Launcher > Terminal.

Затем, выполнить команды:
conda create -n <ENV_NAME>
conda activate <ENV_NAME>

Деактивация:
conda deactivate
Удаление:
conda remove --name <ENV_NAME> --all

Документация по работе с окружениями
в Anaconda.
Документация в Conda.

#Python #Программирование

Артем Лещев
🔄 ♻️ Работаем с командами Git

Помню, мне доводилось деплоить в продакшен, а потом срочно откатывать изменения из-за того, что прод прилёг отдохнуть🏖. Это было 3 года назад, когда я работал менеджером ИТ-проектов.

😎 Не будем ограничиваться веб-мордами хостингов кода и изучим Git-команды. Попробуем отправить код из Anaconda Cloud в GitHub-репозиторий! По итогу, получим практическое представление о работе с Git.

Предусловия:

0⃣ Регистрируемся на GitHub. Создаем репозиторий. Грузим туда файлы с кодом. Достаточно будет файла test.py с кодом print("Hello world")

1⃣ Регистрируемся на Anaconda.com. Заходим на Jupyter Notebook.

Начинаем изучать команды Git:

2⃣ Прежде всего, склонируем GitHub-репозиторий в Анаконду, используя HTTP.

Открываем "New Launcher" (Ctrl + Shift + L). Далее Terminal. В терминале вводим команду:
git clone {HTTP-ссылка на репу}

В конце ссылки можно добавить .git

Далее заходим в склонированный репозиторий:
cd {название репы}


3⃣ Создаем новую ветку в которой будем вести разработку, и сразу на нее переключаемся:
git checkout -b {название ветки: test, feature и т.п.}

Например: git checkout -b feature

4⃣ Колдуем. Вносим правки в код:
Было: print("Hello world")
Стало: print("Хочу 300k/сек")

5⃣ Проверим изменения:
git status

6⃣ Добавляем файлы в индекс (stage area). Это промежуточная область между рабочим каталогом (где делаем изменения в файлах) и репозиторием. Индекс позволяет выбирать какие файлы отправить в коммит.

🔸 Добавить все измененные файлы (вводить с точкой):
git add .

🔸 Добавить конкретный файл:
git add {название файла вместе с его расширением}

7⃣ Создаём коммит (сохранение изменений). Флаг -m означает message. Можно написать пояснение:
git commit -m "Пофиксил баги, надеюсь новых не добавил"

8⃣ Отправляем нашу ветку в репу на GitHub:
git push origin {название ветки}

В нашем случае: git push origin feature

origin — это имя, которое по умолчанию присваивается нашему удаленному репозиторию на GitHub.

9⃣ Проходим аутентификацию.
Вводим свой username, а для password вводим классический токен.
Создается токен по ссылке.

1⃣ 0⃣ Идем на GitHub, открываем репозиторий и видим таб "2 Branches". Кликаем.
Видим, что помимо main, появилась и наша новая ветка.
Заходим в нее, заходим в отредактированный файл и видим изменения: print("Хочу 300k/сек")
Делаем pull request (запрос на внедрение кода) из интерфейса, затем мержим в main.
___
😎 Понравился пост? Подписывайся, чтобы не пропустить следующие!

Артем Лещев
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👏1
📋 «Доброе начало — полдела откачало». Мой чек-лист передачи проекта от сейлз-менеджера к руководителю проекта.

Участвую в конкурсе «Продолжи мысль» от @systems_education

Данный пост — мой полевой опыт. В 2022-2023 гг. я работал руководителем ИТ-проектов в смоленской веб-студии, где одновременно вел несколько проектов. Затем происходила ситуация как на картинке.

В один день встал вопрос: как мне эффективно получать от менеджера по продажам (далее — сейлз) информацию о новом проекте? Иными словами — мне нужен был качественный онбординг в проект. Я придумал как его организовать.

🔴 AS-IS.
Сейлз набрасывал концептуальную структуру проекта, затем голосом вводил меня в курс дела.

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

🟢 TO-BE.
Я составил чек-лист, по которому сейлз максимально подробно описывал для меня проект. Всего было 5 разделов:

1. Описание проекта в свободной форме

Здесь сейлз своими словами заполнял следующую информацию:

(а) Давал контакты для связи с ЛПР.

(б) Давал характеристику ЛПР.

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

(в) Описывал текстом бизнес-цели и пользовательские цели проекта.

(г) Давал текстовые комментарии к концептуальной структуре проекта.

(д) Давал текстовое описание к референсам, которые обсуждал с клиентом. Что конкретно понравилось на каждой веб-морде.

(е) Отдельным пунктом я просил описать те референсы, которые поступили от самого заказчика.

2. Какой функционал главный?

Как говорил Павел Дуров: «Самое главное — уметь отличать самое главное». Сейлз мне расписывал что у клиента "болит" сильнее всего, в плане функциональных требований.

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

3. Что уже 100% определено и согласовано?

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

4. Что еще предстоит уточнить и согласовывать?

Список вопросов и проблем, которые стоит обсудить и решить на моем первом установочном созвоне с ЛПР, а также по ходу реализации проекта в целом.

5. Какое у сейлза субъективное мнение о проекте?

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

📈 ИТОГ (4 пункта).

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

Отсутствие документации на проекте – всегда боль. Ондорбинг в проект стал структурированнее и понятнее.

2. Устное обсуждение с сейлзом стало существенно более структурированным.


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

3. Я настоял на том, чтобы сейлз организовывал совместный созвон с заказчиком.

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

4. Повысилось качество проработки требований и написания ТЗ.

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

Как гласит пословица: "Доброе начало – полдела откачало". Благодаря чек-листу я четко знал какие задавать вопросы ЛПРу; как подступиться к написанию ТЗ; что выносить на обсуждение с программистами.

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

#продолжи_мысль_SE #Менеджмент #Требования

Артем Лещев
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
😄 С днем знаний!

Я закончил школу 10 лет назад и даже не думал, что буду работать в ИТ. Сам по образованию историк и могу преподавать в колледже.

У меня было 2 учительницы информатики. У каждой был свой подход к преподаванию:

😁 У первой (до 9 класса) мы играли в CS, подставляли наши фотки вместо Марио в эмуляторе Денди, и просто взламывали Пентангон залипали в телефон.

🐧 У второй (10-11) мы записывали определения терминов: что такое "информация", что такое "данные"... Ни о каком программировании на Python, как учат школьников сейчас, даже речи не шло. Кажется, пару раз кликали Excel, но это не точно.

Когда я спросил у учительницы (10-11), читает ли она какую-нибудь ИТ-литературу, то она сказала, что нет. Только то, что требуется для проведения занятия. Сейчас она уже несколько лет как переквалифицировалась в таргетолога и успешно настраивает рекламус московским толстосумам.
___
😎 Понравился пост? Подписывайся, чтобы не пропустить следующие!

Артем Лещев
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🎉 Сегодня 13 сентября. 256-й день года. С днем программиста!

256, это 2⁸, то есть наибольшее количество различных значений, которые можно выразить одним байтом. Если кому интересно почему в байте 8 бит, то могу посоветовать вот эту статью. Спойлер: так исторически сложилось, 6-битный вариант тоже использовали. 8 достаточно для обработки букв обоих регистров и символов.

Также 256 — это максимальная целая степень числа 2, которая не превышает количество дней в году (365 или 366).

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

На QnA Habr мне когда-то попался безумно интересный комментарий (10-летней давности!) на что разрабы обращают внимание, во время код-ревью. 282 лайка! Это требования к PHP-коду, но там есть ряд вещей, которые будут: во-первых, актуальны для других языков; во-вторых, стоит иметь ввиду всем: менеджерам, аналитикам, тестировщикам.
Более формализовано, есть на Гитхабе у автора:
https://github.com/index0h/php-conventions

🙃 9 сентября, кстати, праздновался день лучшего друга программиста тестировщика. 9 сентября 1947 года в Гарвардском университете тестировали вычислительную машину Mark II Aiken Relay Calculator и нашли мотылька (по англ. moth), застрявшего между контактами реле. Грейс Хоппер (разработчица первого компилятора) тогда произнесла «bug», более общее слово для большинства мелких насекомых.
___
😎 Понравился пост? Подписывайся, чтобы не пропустить следующие!

Артем Лещев
Please open Telegram to view this post
VIEW IN TELEGRAM
😁 Частый вопрос на SQL-собеседованиях.

Какое минимальное и максимальное количество записей могут вывести INNER JOIN, LEFT JOIN, FULL JOIN, и какой должен быть набор значений? Сталкивались с таким вопросом? 🙃

Предварительные условия:

1. Обычно просят считать, что таблица "t1" содержит 10 значений, а таблица "t2" — 100. Для облегчения тестирования, мы будем считать, что в "t1" — 2 значения, а в "t2" — три.

2. Я добавил в примеры null-значения, для доп. иллюстрации действия.

3. Будем исходить из наиболее типичного условия фильтрации: t1.id = t2.id.

4. Разбираться будем на примере PostgreSQL.

Погнали!

INNER JOIN

Минимум — 0 записей.
Набор данных — когда совпадений не найдено. То есть значения в одной таблице полностью отличаются от значений в другой (если есть null, то помним, что они друг другу не равны).
t1 = 1, null
t2 = 2, null, null

Максимум — декартово произведение (в нашем случае 2 х 3 = 6).
Набор данных — в обоих таблицах одни и те же значения, например, везде единицы.
t1 = 1, 1
t2 = 1, 1, 1

LEFT JOIN

Минимум — количество записей в таблице, указанной во FROM. Соответственно, сюда надо поместить таблицу с меньшим кол-вом записей.
Набор данных — когда в обоих таблицах только разные значения. Нет совпадений. Соответственно, первая таблица (во FROM) отобразит все свои записи, и им приджойнятся null.
t1 = 1, null
t2 = 2, 3, null

Максимум — аналогично INNER JOIN. Декартово произведение (в нашем случае 2 х 3 = 6).
Набор данных — в обоих таблицах одни и те же значения, например, везде единицы.
t1 = 1, 1
t2 = 1, 1, 1

RIGHT JOIN

Разница этих джойнов в том, что при LEFT будут отображены все записи таблицы из FROM, а при RIGHT — все записи таблицы из JOIN.

Минимум — количество записей в таблице, указанной после ключевых слов RIGHT JOIN. Соответственно, сюда надо поместить таблицу с меньшим кол-вом записей.
Набор данных — когда в обоих таблицах только разные значения. Нет совпадений. Соответственно, вторая таблица (не во FROM, а та, что после RIGHT JOIN) отобразит все свои записи, и им приджойнятся null.
t1 = 1, null
t2 = 2, 3, null

Максимум — аналогично LEFT JOIN. Декартово произведение (в нашем случае 2 х 3 = 6).
Набор данных — в обоих таблицах одни и те же значения, например, везде единицы.
t1 = 1, 1
t2 = 1, 1, 1

FULL JOIN

Минимум — количество записей в бóльшей таблице (в нашем случае 3), при этом без разницы где она будет указана: во FROM или после JOIN.
Набор данных — каждое значение первой таблицы уникально и имеет только один аналог во второй таблице.
Соответственно, все значения первой таблицы найдут свою пару во второй. А лишние значение второй таблицы получат null.
t1 = 1, 2
t2 = 1, 2, 3

Максимум — декартово произведение (в нашем случае 2 х 3 = 6).
Набор данных — в обоих таблицах одни и те же значения, например, везде единицы.
t1 = 1, 1
t2 = 1, 1, 1

А что если все значения будут разными? Например:
t1 = null, null
t2 = null, null, null

отобразит 5 записей, т.к. FULL, LEFT, RIGHT джойны начинают выполняться с INNER-механики! А INNER JOIN для null-значений вернет 0 совпадений! Далее выполняется LEFT и RIGHT, итого 2 + 3 = 5 записей.

✏️ ИТОГО

Минимум:
INNER — 0;
LEFT — кол-во записей таблицы, указанной во FROM;
RIGHT — кол-во записей таблицы, указанной в RIGHT JOIN;
FULL — кол-во записей большей таблицы.
Максимум: INNER, LEFT, FULL создадут декартово произведение.

Если t1 имеет 10 записей, а t2 1000, то:
Минимум:
INNER — 0;
LEFT — 10 (указываем t1 во FROM);
RIGHT — 10 (указываем t1 после JOIN);
FULL — 100.
Максимум: 1000 записей.

🐧 Примеры кода можно посмотреть здесь:
https://dbfiddle.uk/jJjivYdm
___
Понравился пост? Подписывайся, чтобы не пропустить следующие.

Артем Лещев
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2😈2