Backend
3.95K subscribers
35 photos
707 links
Комьюнити Backend программистов.
Python, Java, Golang, PHP, C#, C/C++, DevOps

Сайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp
Download Telegram
Что такое Маршалинг и чем он отличается от Сериализации максимально содержательно и с примерами

Маршалинг (Marshalling) и сериализация (Serialization)
- это процессы преобразования данных из структурированного формата (например, объекты в памяти) в формат, который может быть передан или сохранен (например, в виде байтового потока), и наоборот. Оба термина часто используются в контексте передачи данных между различными приложениями или процессами.

Маршалинг (Marshalling):


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

import pickle

import json

# Преобразование объекта Python в JSON-строку (маршалинг)
data = {'name': 'John', 'age': 30, 'city': 'New York'}
json_string = json.dumps(data)
print(json_string)


Здесь объект data (словарь Python) маршализуется в JSON-строку с помощью функции json.dumps(). Результатом будет строка {"name": "John", "age": 30, "city": "New York"}.

Сериализация (Serialization):


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

import pickle

# Сериализация объекта Python в бинарный формат (pickle)
data = {'name': 'Alice', 'age': 25, 'city': 'Los Angeles'}
with open('data.pkl', 'wb') as f:
pickle.dump(data, f)


Здесь объект data (словарь Python) сериализуется в бинарный формат с помощью модуля pickle и сохраняется в файл data.pkl.

Отличия между Маршалингом и Сериализацией:


• Формат вывода: Маршалинг чаще всего приводит к преобразованию данных в текстовый формат (например, JSON), который читаем человеком. Сериализация может быть бинарной или текстовой и предназначена для сохранения данных или передачи между системами.

• Цель использования: Маршалинг чаще всего используется для передачи данных через сеть или взаимодействия между различными приложениями. Сериализация чаще всего используется для сохранения состояния объектов или данных в файлы.

• Используемые форматы: Маршалинг часто осуществляется в формате, понятном различным системам (например, JSON для веб-сервисов). Сериализация может быть более специфичной и привязанной к определенному формату (например, использование pickle для сериализации объектов Python).

В целом, маршалинг и сериализация представляют собой важные процессы для обмена и сохранения данных в программировании, и различаются преимущественно по форматам вывода и целям использования.
5👍4🤯1
Задача: Сделать конвейер чисел

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

Довольно частая задача, более подробно можно почитать тут: https://blog.golang.org/pipelines


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

Как всегда, решение закину следующим постом👇
Решение задачи «Сделать конвейер чисел»

package main

import (
"fmt"
)

func main() {
naturals := make(chan int)
squares := make(chan int)

go func() {
for x := 0; x <= 10; x++ {
naturals <- x
}
close(naturals)
}()

go func() {
for x := range naturals {
squares <- x * x
}
close(squares)
}()

for x := range squares {
fmt.Println(x)
}
}
​​Вышла Node.js 22

По данным OpenNET, основные изменения и дополнения в Node.js 22:

• движок V8 обновлён до версии 12.4, применяемой в Chromium 124;

• включён по умолчанию оптимизирующий JIT-компилятор Maglev, нацеленный на быструю генерацию высокопроизводительного машинного кода для активно используемого кода на JavaScript. Включение Maglev позволяет заметно ускорить работу короткоживущих CLI-приложений, не выполняющих длительных операций, например, время прохождения теста Jetstrea сокращается на 7.5%, а теста Speedometer на 5%;

• ускорена работа с потоками за счёт увеличения значения опции highWaterMark с 16 KB до 65 KB (определяет лимит, до которого выполняется буферизация записи). Изменение приводит к увеличению потребления памяти, поэтому приложениям, рассчитанным на работу с ограниченным объёмом ОЗУ, возможно, потребуется вернуть старое значение через вызов setDefaultHighWaterMark();

• повышена производительность API fetch() и test runner за счёт повышения эффективности создания экземпляров AbortSignal. Повышена производительность API, связанных с синхронной работой с файловыми системами;

• предоставлена экспериментальная возможность использования вызова "require()" для загрузки JavaScript-модулей ESM (ECMAScript Modules) в синхронном режиме. ESM-модули применяются в браузерах и идут на смену модулям CommonJS, специфичным для Node.js. Для загрузки через "require()" ESM-модуль должен выполняться в синхронном режиме (без await на верхнем уровне). Поддержка включается через флаг "--experimental-require-module";

• добавлена экспериментальная возможность запуска скриптов, определённых в файле package.json, используя команду "--run ";

• в категорию стабильных переведена команда "node --watch" с реализацией режима наблюдения, обеспечивающего перезапуск процесса при изменении импортированного файла (например, в случае выполнения "node --watch index.js" процесс будет автоматически перезапущен при изменении index.js);

• стабилизирована встроенная реализация API WebSocket, позволяющего использовать WebSocket в режиме клиента без установки дополнительных зависимостей;

• добавлена частичная поддержка API Navigator;

• в API Webstreams добавлена поддержка формата сжатия deflate-raw;

• в модуль node:fsmodule добавлены функции glob и globSync для сопоставления файловых путей по образцу;

• улучшена обработка некорректно настроенных стеков IPv6. Реализован алгоритм Happy Eyeballs для быстрого отката в случае проблем с работой IPv6;

• объявлен устаревшим API util;

• обновлены версии зависимостей: npm 10.5.1, libuv 1.48.0, simdutf 5.2.3, c-ares 1.28.1, zlib 1.3.0.1-motley-24c07df, simdjson to 3.8.0, ada 2.7.7 и undici 6.6.0.

Поддержка Node.js 22.x будет осуществляться до 30 апреля 2027 года. Сопровождение прошлой LTS-ветки Node.js 20.x продлится до апреля 2026 года, а позапрошлой LTS-ветки 18.x — до апреля 2025 года. Сопровождение промежуточной ветки Node.js 21.x будет прекращено 1 июня 2024 года.


Ставь 🔥 если хочешь больше новостей!
👍31🔥1
Сравнение различных баз данных: Когда выбирать SQL, а когда NoSQL?

Сравнение различных типов баз данных - SQL и NoSQL - зависит от конкретных потребностей проекта, его структуры данных и требований к масштабируемости, производительности и консистентности данных. Давайте рассмотрим основные аспекты выбора между SQL и NoSQL с примерами.

Когда выбирать SQL:


Структурированные данные: Если ваши данные имеют жесткую структуру и связи между ними легко описать в виде таблиц, то SQL базы данных, такие как MySQL, PostgreSQL или SQLite, будут лучшим выбором. SQL базы данных отлично подходят для приложений, где необходимо соблюдать строгие правила целостности данных.

Транзакционность: Если ваше приложение требует поддержки транзакций с ACID (Atomicity, Consistency, Isolation, Durability) свойствами, то SQL базы данных и их транзакционные возможности подходят лучше. Это важно для финансовых приложений, систем управления инвентаризацией и других приложений, где целостность данных является критически важной.

CREATE TABLE Users (
UserID INT PRIMARY KEY,
Username VARCHAR(50),
Email VARCHAR(100)
);


Когда выбирать NoSQL:


Гибкие и неструктурированные данные: Если ваше приложение работает с гибкими или неструктурированными данными, такими как JSON, XML или документы, то NoSQL базы данных, такие как MongoDB, Couchbase или Cassandra, могут быть более подходящим выбором. Они позволяют хранить и обрабатывать данные без явного определения схемы.

Масштабируемость: NoSQL базы данных часто предоставляют горизонтальное масштабирование (scaling out), что позволяет эффективно масштабировать приложение с ростом количества данных или нагрузки. Это особенно полезно для приложений с высокой нагрузкой и большими объемами данных, таких как социальные сети или аналитические приложения.

{
"userID": 123,
"username": "john_doe",
"email": "[email protected]",
"posts": [
{"title": "Post 1", "content": "Content 1"},
{"title": "Post 2", "content": "Content 2"}
]
}


В этом примере каждый документ представляет собой отдельную запись о пользователе с полями userID, username, email и массивом posts, содержащим посты пользователя.

В итоге, выбор между SQL и NoSQL базами данных зависит от конкретных требований вашего приложения по структуре данных, требованиям к масштабируемости и производительности, а также предпочтений команды разработчиков. Обе модели имеют свои преимущества и ограничения, и выбор должен быть сделан на основе тщательного анализа и оценки потребностей проекта.
👍7
Что такое RabbitMQ

RabbitMQ - это мощная и гибкая система сообщений (Message Queue), которая обеспечивает асинхронную связь между различными компонентами системы.

Основные компоненты RabbitMQ:


1. Producer (Производитель): Программа или сервис, который отправляет сообщения в RabbitMQ.
2. Queue (Очередь): Хранилище сообщений в RabbitMQ. Сообщения остаются в очереди до тех пор, пока они не будут обработаны и прочитаны Consumer'ом.
3. Consumer (Потребитель): Программа или сервис, который получает сообщения из RabbitMQ и обрабатывает их.
4. Exchange (Обменник): Компонент, который получает сообщения от Producer'а и направляет их в одну или несколько очередей. Exchange определяет, как сообщения будут маршрутизироваться.

Пример использования RabbitMQ:


Предположим, у вас есть приложение для обработки заказов в интернет-магазине. Когда пользователь размещает заказ, ваш веб-сервер отправляет сообщение в RabbitMQ, содержащее детали заказа. Затем приложение для обработки заказов, подписанное на соответствующую очередь в RabbitMQ, получает сообщение, обрабатывает заказ и отправляет его на доставку.

import pika

# Подключение к RabbitMQ серверу
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# Создание очереди
channel.queue_declare(queue='orders')

# Отправка сообщения в очередь
channel.basic_publish(exchange='', routing_key='orders', body='New order: #123')

print(" [x] Sent 'New order: #123'")

# Закрытие соединения
connection.close()


В этом примере Python-программа отправляет сообщение "New order: #123" в очередь "orders" RabbitMQ. Другое приложение, подписанное на эту очередь, будет получать и обрабатывать это сообщение.

RabbitMQ обладает широким спектром возможностей, таких как управление ошибками, маршрутизация сообщений, подтверждения доставки и многое другое, что делает его очень гибким и мощным инструментом для построения асинхронной архитектуры приложений.
👍14
Задача: Написать WorkerPool с заданной функцией

Довольно распространенная задача, плюс подобные задачи встречаются на практике.


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

Решение будет следующим постом ⬇️
👍1🔥1
Решение:


package main

import (
"fmt"
)

func worker(id int, f func(int) int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- f(j)
}
}

func main() {

const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)

multiplier := func(x int) int {
return x * 10
}

for w := 1; w <= 3; w++ {
go worker(w, multiplier, jobs, results)
}

for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)

for i := 1; i <= numJobs; i++ {
fmt.Println(<-results)
}
}
🔥6
Что такое gRPC максимально содержательно и с примерами

gRPC (gRPC Remote Procedure Call) - это высокопроизводительный фреймворк для удаленного вызова процедур (RPC), разработанный компанией Google. Он использует простой и эффективный механизм взаимодействия между клиентом и сервером, основанный на протоколе HTTP/2 для передачи данных и Protocol Buffers (protobuf) для сериализации структурированных данных.

Основные характеристики gRPC:


1. Простота использования: gRPC позволяет определять удаленные сервисы с использованием простого и понятного синтаксиса Protocol Buffers. Он обеспечивает прозрачное взаимодействие между клиентом и сервером, скрывая сложности низкоуровневых деталей сетевого взаимодействия.

2. Высокая производительность: Фреймворк использует протокол HTTP/2 для эффективной передачи данных между клиентом и сервером. Это позволяет уменьшить задержки и улучшить производительность сетевых запросов.

3. Поддержка множества языков программирования: gRPC поддерживает множество языков программирования, включая C++, Java, Python, Go, Ruby и многие другие. Это позволяет создавать многоязыковые приложения с использованием единого RPC-интерфейса.

4. Сильная типизация данных: Благодаря использованию Protocol Buffers, gRPC обеспечивает сильную типизацию данных, что делает взаимодействие между клиентом и сервером более надежным и безопасным.

5. Поддержка различных типов RPC: gRPC поддерживает различные типы RPC, включая унарный (Unary), сервер-стриминг (Server-streaming), клиент-стриминг (Client-streaming) и двусторонний поток (Bidirectional-streaming) RPC. Это позволяет выбирать наиболее подходящий тип взаимодействия в зависимости от требований приложения.

Следующим постом разберем примеры использования gRPC 👇
👍11
Пример использования gRPC:

Рассмотрим простой пример использования gRPC для создания клиент-серверного приложения на Python.

1. Определение сервиса и сообщений в файле example.proto с использованием синтаксиса Protocol Buffers:

syntax = "proto3";

message HelloRequest {
string name = 1;
}

message HelloResponse {
string message = 1;
}

service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}


2. Генерация кода на основе файла example.proto с помощью компилятора Protocol Buffers:

protoc -I=. --python_out=. --grpc_python_out=. example.proto


3. Создание сервера на Python с использованием gRPC:

import grpc
import example_pb2
import example_pb2_grpc

class GreeterServicer(example_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return example_pb2.HelloResponse(message=f"Hello, {request.name}!")

def serve():
server = grpc.server(grpc.insecure_server())
example_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()

if name == 'main':
serve()


4. Создание клиента на Python с использованием gRPC:

import grpc
import example_pb2
import example_pb2_grpc

def run():
channel = grpc.insecure_channel('localhost:50051')
stub = example_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(example_pb2.HelloRequest(name='world'))
print
Использование JWT и OAuth для аутентификации и авторизации в веб-приложениях

JWT (JSON Web Token) и OAuth - это два распространенных стандарта для реализации аутентификации и авторизации в веб-приложениях.


JWT - это компактный и самодостаточный способ представления информации об аутентификации в форме JSON, которая может быть передана между двумя сторонами как часть HTTP запроса или в теле. Он состоит из трех частей: заголовка (header), полезной нагрузки (payload) и подписи (signature). Заголовок содержит информацию о типе токена и используемом алгоритме шифрования. Полезная нагрузка содержит информацию об аутентифицированном пользователе или другие данные. Подпись обеспечивает проверку целостности данных.

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

Пример использования JWT и OAuth в веб-приложении:


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

Сервер аутентификации проверяет учетные данные пользователя и создает JWT токен с информацией об аутентифицированном пользователе (например, идентификатор пользователя, роль и срок действия токена).

Сервер возвращает JWT токен клиентскому приложению.

При последующих запросах клиентское приложение включает JWT токен в заголовок Authorization.

Сервер проверяет подлинность токена и авторизует запрос на основе информации в токене.

Следующим постом рассмотрим пример кода на Python с использованием библиотеки Flask для реализации аутентификации с помощью JWT ⬇️
👍5
Пример кода на Python с использованием библиотеки Flask для реализации аутентификации с помощью JWT:

from flask import Flask, jsonify, request
import jwt
from functools import wraps

app = Flask(name)
app.config['SECRET_KEY'] = 'secret'

def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token:
return jsonify({'message': 'Token is missing!'}), 401
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
except:
return jsonify({'message': 'Token is invalid!'}), 401
return f(*args, **kwargs)
return decorated

@app.route('/login', methods=['POST'])
def login():
auth = request.authorization
if auth and auth.password == 'password':
token = jwt.encode({'username': auth.username}, app.config['SECRET_KEY'])
return jsonify({'token': token.decode('UTF-8')})
return jsonify({'message': 'Could not verify!'}), 401

@app.route('/protected', methods=['GET'])
@token_required
def protected():
return jsonify({'message': 'This is protected route!'})

if name == 'main':
app.run(debug=True)


В этом примере, при запросе на /login пользователь предоставляет учетные данные и, если они верны, сервер создает JWT токен, который включает в себя имя пользователя. После этого, для доступа к защищенному маршруту /protected, клиент должен предоставить этот токен в заголовке Authorization. Функция token_required обеспечивает аутентификацию пользователя на основе JWT токена.
👍8
⚙️ Обработка NULL с DISTINCT

with new_table as (
select patient_id from patients
UNION
select null
)

select
count()
, count(distinct patient_id)
, count(patient_id)

from new_table


Результатом запроса будет значение 4531 для столбца COUNT() и 4530 для двух оставшихся столбцов. Когда вы указываете столбец, ключевое слово COUNT исключает нулевые значения.Однако, при использовании звездочки в подсчет включаются значения NULL.

Это может сбивать с толку при проверке, является ли столбец первичным ключом, поэтому я посчитал нужным упомянуть об этом.
1
Что такое ACID максимально содержательно и с примерами

ACID (Atomicity, Consistency, Isolation, Durability) - это набор основных принципов транзакционной обработки в базах данных, обеспечивающих надежность и целостность данных.

Вот более подробное объяснение каждого из принципов:

Atomicity (Атомарность):

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

Пример: Представьте, что пользователь хочет выполнить банковский перевод со счета A на счет B. Если перевод прошел успешно, то деньги будут вычтены со счета A и добавлены на счет B. Если произошла ошибка в середине процесса (например, проблемы с сетью), ни один из счетов не будет изменен.

Consistency (Согласованность):

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

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

Isolation (Изоляция):

Этот принцип гарантирует, что выполнение одной транзакции не зависит от выполнения других транзакций, которые происходят параллельно. Изоляция предотвращает влияние одной транзакции на другие транзакции.

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

Durability (Долговечность):

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

Пример: После того, как транзакция перевода средств выполнена успешно и пользователь получил подтверждение, долговечность гарантирует, что эти изменения останутся в базе данных и не будут потеряны даже в случае сбоя системы.
👍12
Clean Architecture

Clean Architecture - это методология проектирования программного обеспечения, предложенная Робертом Мартином (также известным как Uncle Bob), которая призвана создать гибкую, легко поддерживаемую и расширяемую архитектуру приложения.

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

Основные компоненты Clean Architecture включают в себя:


Entities (Сущности): Это основные объекты, которые представляют бизнес-логику приложения. Сущности содержат логику и данные, специфичные для предметной области.

Use Cases (Случаи использования):
Это компоненты, которые описывают то, что система должна делать. Они содержат логику, которая координирует взаимодействие между сущностями и другими компонентами.

Interfaces (Интерфейсы):
Это абстракции, которые определяют способ взаимодействия между компонентами системы. Интерфейсы разделяют код на уровни и определяют контракты между компонентами.

Frameworks and Drivers (Фреймворки и драйверы):
Это внешние компоненты, такие как фреймворки, библиотеки и инструменты, которые используются для реализации конкретных функций или подключения системы к внешним ресурсам.

Пример применения Clean Architecture:


Представьте, что у вас есть веб-приложение для управления задачами. Вы можете реализовать Clean Architecture, разделив приложение на следующие компоненты:

Entities: Сущности могут включать в себя объекты, такие как Task (Задача) с полями, такими как название, описание, статус и т. д.

Use Cases: Случаи использования могут включать в себя логику для создания, чтения, обновления и удаления задач, а также выполнение других операций, связанных с управлением задачами.

Interfaces:
Интерфейсы могут определять, как компоненты приложения будут взаимодействовать между собой, например, через REST API для взаимодействия с веб-интерфейсом пользователя или через сервисы для доступа к базе данных.

Frameworks and Drivers:
Фреймворки и драйверы могут включать в себя фреймворки для разработки веб-приложений, библиотеки для работы с базами данных и инструменты для автоматизации тестирования.

Clean Architecture способствует созданию гибких, модульных и легко поддерживаемых приложений, которые легко масштабировать и изменять.
👍4🔥2🤔1
Как и просили, делаю пример применения Clean Architecture в коде

Рассмотрим пример применения Clean Architecture на простом веб-приложении для управления задачами. Мы разделим приложение на несколько слоев: представление (View), бизнес-логику (Use Cases) и данные (Repositories). Для простоты мы будем использовать Python и фреймворк Flask для реализации веб-интерфейса.

# entities.py
class Task:
def init(self, title, description, status):
self.title = title
self.description = description
self.status = status

# repositories.py
class TaskRepository:
def get_task_by_id(self, task_id):
# код для получения задачи из базы данных
pass

def save_task(self, task):
# код для сохранения задачи в базу данных
pass

# use_cases.py
class TaskManager:
def init(self, task_repository):
self.task_repository = task_repository

def create_task(self, title, description):
task = Task(title=title, description=description, status='todo')
self.task_repository.save_task(task)

def get_task(self, task_id):
return self.task_repository.get_task_by_id(task_id)

# app.py (Flask приложение)
from flask import Flask, request, jsonify
from entities import Task
from repositories import TaskRepository
from use_cases import TaskManager

app = Flask(name)
task_repository = TaskRepository()
task_manager = TaskManager(task_repository)

@app.route('/tasks', methods=['POST'])
def create_task():
data = request.json
title = data.get('title')
description = data.get('description')
task_manager.create_task(title, description)
return jsonify({'message': 'Task created successfully'})

@app.route('/tasks/<task_id>', methods=['GET'])
def get_task(task_id):
task = task_manager.get_task(task_id)
return jsonify({'title': task.title, 'description': task.description, 'status': task.status})

if name == 'main':
app.run(debug=True)


В этом примере:

entities.py содержит базовую сущность задачи.
repositories.py содержит репозиторий для доступа к данным задачи.
• use_cases.py содержит бизнес-логику приложения (создание и получение задачи).
app.py - это веб-приложение Flask, которое обрабатывает HTTP-запросы и использует компоненты бизнес-логики для создания и получения задач.

Этот пример демонстрирует, как Clean Architecture разделяет приложение на независимые слои, что делает его более гибким, легко поддерживаемым и тестируемым. Каждый компонент отвечает только за свою часть функциональности, что делает его более независимым и переносимым.
3👍2🔥2
​​10 причин, по которым стоит выбрать Django вместо FastAPI

FastAPI предлагает производительное, асинхронное, компактное и современное решение для разработки бэкенда и API на Python по сравнению с более зрелым, но несколько более громоздким Django. И все же многие опытные бэкендеры предпочитают Django.

Проверенная надежность вместо модных фишек

Стабильность – превыше всего, а Django – образец стабильности, с минимальным количеством серьезных изменений и регрессий на протяжении многих лет. Каждое обновление тщательно тестируется, а сам фреймворк имеет минимум внешних зависимостей, что помогает избежать значительных проблем.

Обилие справочных ресурсов

За 18 лет существования Django в интернете накопилось огромное количество ресурсов, многие из которых до сих пор актуальны. Ответы на Stack Overflow остаются действительными годами, а ChatGPT предоставляет корректные ответы, основанные на огромном объеме полезного и релевантного контента.

Гибкость

Django одинаково хорошо подходит и для бэкенда, и для фулстек-разработки.

Более удобная ORM

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

Ограниченная полезность асинхронных возможностей

Одним из преимуществ FastAPI считается встроенная поддержка ASGI-сервер, но на практике такая функциональность требуется не так уж часто. Для действительно асинхронных задач достаточно инструментов вроде Celery, а для вебсокетов можно использовать решения типа Soketi или Pusher.

Вводящие в заблуждение утверждения о «меньшем количестве шаблонного кода»

Легкость запуска проекта уровня hello world не равнозначна простоте управления и масштабирования со временем.

Ценность конвенций

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

Производительность – не самое главное

Хотя Django – не самый производительный фреймворк, особенно в сравнении с FastAPI, на самом деле навыки разработчика влияют на проблемы с производительностью гораздо больше, чем внутренние возможности используемой технологии. Кроме того, не каждый проект требует экстремальной производительности, а для тех, что требуют, Python – не лучший выбор.

Потенциальные проблемы с поддержкой проекта

В отличие от FastAPI, разработкой и поддержкой Django занимается большая команда.

Иногда лучше выбрать TypeScript-фреймворк

Для проектов с относительно простым бэкендом оптимальным выбором может быть не Django и не FastAPI, а фреймворк типа AdonisJS, в сочетании с ORM вроде Prisma: это упрощает управление проектом за счет единого языка для фронтенда и бэкенда.
👍3😁3🤔2
​​Протоколы TLS/SSL максимально содержательно и с примерами

Протоколы TLS (Transport Layer Security) и SSL (Secure Sockets Layer) - это криптографические протоколы, которые обеспечивают защищенную передачу данных в сети Интернет. Они используются для обеспечения конфиденциальности, целостности и подлинности данных, передаваемых между клиентом и сервером.

Протокол SSL был разработан компанией Netscape и стал широко использоваться для защищенной передачи данных в Интернете. Однако из-за уязвимостей и проблем безопасности SSL, протокол был заменен более современным и безопасным протоколом TLS.

Протоколы TLS и SSL работают на разных уровнях сетевой модели OSI


SSL/TLS Handshake Protocol: Этот протокол используется для установления защищенного соединения между клиентом и сервером. В процессе рукопожатия происходит обмен криптографическими ключами, установка параметров шифрования и аутентификация сторон.

SSL/TLS Record Protocol: Этот протокол используется для защищенной передачи данных между клиентом и сервером. Он обеспечивает конфиденциальность, целостность и аутентификацию сообщений путем шифрования и аутентификации данных.

Когда вы заходите на защищенный сайт (например, сайт банка или интернет-магазина), ваш браузер и сервер взаимодействуют по следующему сценарию:

1. Браузер отправляет запрос на сервер.
2. Сервер отвечает с помощью сертификата SSL/TLS, который содержит открытый ключ сервера.
3. Браузер проверяет сертификат, чтобы убедиться, что он действителен и принадлежит запрашиваемому серверу.
4. Если сертификат действителен, браузер и сервер выполняют SSL/TLS Handshake Protocol для установления защищенного соединения.
5. После успешного рукопожатия данные между браузером и сервером передаются с использованием SSL/TLS Record Protocol, обеспечивая конфиденциальность и целостность данных.

Протоколы TLS и SSL играют ключевую роль в обеспечении безопасности передачи данных в Интернете и используются в различных сферах, включая веб-браузеры, электронную почту, мессенджеры и другие приложения.
👍5
​​Задача: Сделать кастомную waitGroup на семафоре

Семафор можно легко получить из канала. Чтоб не аллоцировать лишние данные, будем складывать туда пустые структуры.


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

Решение ⬇️

package main

import (
"fmt"
)

type sema chan struct{}

func New(n int) sema {
return make(sema, n)
}

func (s sema) Inc(k int) {
for i := 0; i < k; i++ {
s <- struct{}{}
}
}

func (s sema) Dec(k int) {
for i := 0; i < k; i++ {
<-s
}
}

func main() {
numbers := []int{1, 2, 3, 4, 5}
n := len(numbers)

sem := New(n)

for _, num := range numbers {
go func(n int) {
fmt.Println(n)
sem.Inc(1)
}(num)
}

sem.Dec(n)

}
​​Архитектурный паттерн CQRS максимально содержательно и с примерами

CQRS (Command Query Responsibility Segregation) - это архитектурный паттерн, который предлагает разделять операции записи (команды) и операции чтения (запросы) в приложении. Этот подход позволяет разработчикам создавать более гибкие и масштабируемые системы, а также улучшить производительность и обеспечить согласованность данных.

Основные принципы CQRS:


1. Разделение операций записи и операций чтения: Команды (операции записи) и запросы (операции чтения) обрабатываются отдельно. Это позволяет оптимизировать обработку каждого типа операций и использовать различные модели данных для команд и запросов.

2. Моделирование данных: Для команд и запросов могут использоваться различные модели данных, оптимизированные для конкретных потребностей. Например, для операций записи может использоваться нормализованная модель данных, а для операций чтения - денормализованная модель данных или материализованные представления.

3. Асинхронная обработка: Обработка команд может быть асинхронной и происходить в фоновом режиме, что позволяет улучшить производительность и масштабируемость системы.

Следующим постом рассмотрим пример использования CQRS ⬇️
👍5