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
Решение задачи «Слить N каналов в один»

package main

import (
"fmt"
"sync"
)

func joinChannels(chs ...<-chan int) <-chan int {
mergedCh := make(chan int)

go func() {
wg := &sync.WaitGroup{}

wg.Add(len(chs))

for _, ch := range chs {
go func(ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for id := range ch {
mergedCh <- id
}
}(ch, wg)
}

wg.Wait()
close(mergedCh)
}()

return mergedCh
}

func main() {

a := make(chan int)
b := make(chan int)
c := make(chan int)

go func() {
for _, num := range []int{1, 2, 3} {
a <- num
}
close(a)
}()

go func() {
for _, num := range []int{20, 10, 30} {
b <- num
}
close(b)
}()

go func() {
for _, num := range []int{300, 200, 100} {
c <- num
}
close(c)
}()

for num := range joinChannels(a, b, c) {
fmt.Println(num)
}

}
👍7
Что такое SOAP?

SOAP (Simple Object Access Protocol) - это протокол обмена сообщениями, который используется для передачи структурированных и формализованных данных между компьютерными системами через сеть. SOAP базируется на XML и используется для обмена данными между приложениями, работающими на различных платформах и написанными на разных языках программирования.

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


Простота (Simple): SOAP предоставляет простой и легко понятный способ обмена структурированными данными между клиентом и сервером. Он определяет набор стандартных правил для форматирования и передачи сообщений.

Объектный доступ (Object Access): SOAP позволяет вызывать удаленные процедуры (RPC - Remote Procedure Calls) на удаленном сервере, позволяя клиенту вызывать методы и функции на сервере, как если бы они были локальными.

Протокол (Protocol): SOAP определяет стандартные правила для описания структуры сообщений, методов и параметров вызова. Он обеспечивает возможность сериализации и десериализации данных между различными платформами и языками.

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


• SOAP Envelope: Определяет структуру SOAP-сообщения, включая обязательные элементы, такие как заголовок (Header) и тело (Body).
• SOAP Header: Может содержать дополнительные метаданные, такие как информация об аутентификации, авторизации, безопасности и т.д.
• SOAP Body: Содержит основные данные запроса или ответа. Фактическое содержимое сообщения передается внутри SOAP Body.

Пример SOAP-сообщения:

<soap:Envelope xmlns:soap="https://www.w3.org/2003/05/soap-envelope" xmlns:ns="https://example.com/">
<soap:Header/>
<soap:Body>
<ns:GetUserInfo>
<ns:UserID>123</ns:UserID>
</ns:GetUserInfo>
</soap:Body>
</soap:Envelope>


Пример SOAP-ответа:

<soap:Envelope xmlns:soap="https://www.w3.org/2003/05/soap-envelope" xmlns:ns="https://example.com/">
<soap:Header/>
<soap:Body>
<ns:GetUserInfoResponse>
<ns:UserName>John Doe</ns:UserName>
<ns:Email>[email protected]</ns:Email>
</ns:GetUserInfoResponse>
</soap:Body>
</soap:Envelope>
👍10
​​Чем REST лучше SOAP максимально содержательно и с примерами

REST (Representational State Transfer) и SOAP (Simple Object Access Protocol) - это два основных подхода к созданию веб-сервисов для обмена данными между клиентами и серверами. Вот несколько причин, по которым REST часто считается более привлекательным выбором по сравнению с SOAP:

Простота и легковесность:

REST основан на простом и легковесном архитектурном стиле, который использует стандартные протоколы HTTP (GET, POST, PUT, DELETE) для обмена данными. Это делает REST более простым в использовании и понимании по сравнению с SOAP, который требует более сложных протоколов, таких как HTTP+XML.

Использование стандартных форматов данных:

REST часто использует форматы данных, такие как JSON (JavaScript Object Notation) или XML (Extensible Markup Language), которые легче читать и парсить для различных языков программирования. SOAP, с другой стороны, часто использует XML, который может быть более громоздким и менее удобным для работы.

Гибкость и масштабируемость:

REST предоставляет более гибкий подход к созданию веб-сервисов, позволяя использовать различные HTTP методы для выполнения операций (например, GET для чтения данных, POST для создания данных, PUT для обновления данных, DELETE для удаления данных). Это делает REST более масштабируемым и адаптивным к различным потребностям.

Легкая связь между клиентом и сервером:

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

Следующим постом рассмотрим пример сравнения использования REST и SOAP
4👍1👀1
Пример сравнения использования REST и SOAP для создания веб-сервиса получения информации о пользователе:

RESTful сервис:


GET /api/users/123 HTTP/1.1
Host: example.com
Accept: application/json


HTTP/1.1 200 OK
Content-Type: application/json

{
"id": 123,
"name": "John Doe",
"email": "[email protected]"
}


SOAP сервис:


POST /UserService HTTP/1.1
Host: example.com
Content-Type: text/xml; charset=utf-8
Content-Length: 250

<soap:Envelope xmlns:soap="https://www.w3.org/2003/05/soap-envelope" xmlns:ns="https://example.com/">
<soap:Header/>
<soap:Body>
<ns:GetUserInfo>
<ns:UserID>123</ns:UserID>
</ns:GetUserInfo>
</soap:Body>
</soap:Envelope>


HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8

<soap:Envelope xmlns:soap="https://www.w3.org/2003/05/soap-envelope" xmlns:ns="https://example.com/">
<soap:Header/>
<soap:Body>
<ns:GetUserInfoResponse>
<ns:UserName>John Doe</ns:UserName>
<ns:Email>[email protected]</ns:Email>
</ns:GetUserInfoResponse>
</soap:Body>
</soap:Envelope>


Из примеров видно, что REST использует простые HTTP запросы (GET) для получения данных в формате JSON, тогда как SOAP требует отправки специально сформированных XML-запросов и обработки XML-ответов. REST обеспечивает более прямую и понятную модель взаимодействия, что делает его популярным выбором для создания современных веб-сервисов.
👍2👀1
Что такое Маршалинг и чем он отличается от Сериализации максимально содержательно и с примерами

Маршалинг (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