C# | Вопросы собесов
5.1K subscribers
35 photos
1 file
984 links
Download Telegram
🤔 В какой момент отправляется запрос к базе данных?

Запрос к базе данных отправляется в момент выполнения операций, которые требуют взаимодействия с базой данных. В контексте использования ORM, таких как Entity Framework, это происходит в определенные моменты, когда вы явно вызываете методы для сохранения изменений или выполнения запросов.

🚩Основные моменты отправки запросов к базе данных

🟠При вызове SaveChanges()
Все изменения, сделанные в контексте (например, добавление, обновление, удаление объектов), отправляются в базу данных.
     using (var context = new AppDbContext())
{
var product = new Product { Name = "Example" };
context.Products.Add(product);
context.SaveChanges(); // Запрос к базе данных отправляется здесь
}


🟠При выполнении LINQ-запросов с использованием методов, которые требуют данных из базы
Методы, такие как ToList(), FirstOrDefault(), SingleOrDefault(), Count(), и другие, вызывают выполнение запроса к базе данных для получения данных.
     using (var context = new AppDbContext())
{
var products = context.Products.ToList(); // Запрос к базе данных отправляется здесь
}


🟠При использовании методов асинхронного выполнения запросов
Асинхронные методы, такие как SaveChangesAsync(), ToListAsync(), и другие, также отправляют запросы к базе данных.
     using (var context = new AppDbContext())
{
var product = new Product { Name = "Example" };
context.Products.Add(product);
await context.SaveChangesAsync(); // Запрос к базе данных отправляется здесь
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51
🤔 Что такое DELETE?

Это HTTP-метод, используемый для удаления ресурса на сервере.
1. Указывает серверу удалить указанный ресурс по заданному URL.
2. Также является идемпотентным, так как повторные вызовы не изменяют результат.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍21👀1
🤔 Что такое события?

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

🚩Основные компоненты событий

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

🟠События
События — это специальные делегаты, которые могут быть вызваны для уведомления подписчиков о происходящем действии.

🟠Подписчики
Объекты, которые подписаны на событие и реагируют на его вызов.

🚩Пример использования событий

Определение делегата и события
public class Publisher
{
// Определение делегата
public delegate void NotifyEventHandler(object sender, EventArgs e);

// Определение события на основе делегата
public event NotifyEventHandler Notify;

// Метод, вызывающий событие
public void RaiseEvent()
{
if (Notify != null)
{
Notify(this, EventArgs.Empty);
}
}
}


Подписка на событие и обработчик события
public class Subscriber
{
public void OnNotify(object sender, EventArgs e)
{
Console.WriteLine("Получено уведомление о событии.");
}
}

class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();

// Подписка на событие
publisher.Notify += subscriber.OnNotify;

// Вызов события
publisher.RaiseEvent();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
🤔 Какие бывают самые популярные коды ошибок в HTTP?

1. 400 Bad Request: запрос клиента некорректен.
2. 401 Unauthorized: требуется аутентификация.
3. 403 Forbidden: доступ запрещён.
4. 404 Not Found: ресурс не найден.
5. 500 Internal Server Error: ошибка на стороне сервера.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥4
🤔 Что такое static?

Static - это ключевое слово, которое используется для объявления статических членов в классе. Статические члены принадлежат самому классу, а не его экземплярам.

🚩Основные моменты использования

🟠Поля
Статические поля объявляются с использованием ключевого слова static и принадлежат классу в целом. Все экземпляры класса разделяют одно и то же статическое поле.
public class Example
{
public static int Counter;
}

// Доступ к статическому полю
Example.Counter = 10;
Console.WriteLine(Example.Counter); // Выведет 10


🟠Методы
Статические методы могут быть вызваны без создания экземпляра класса. Статические методы могут обращаться только к другим статическим членам класса.
public class Calculator
{
public static int Add(int a, int b)
{
return a + b;
}
}

// Вызов статического метода
int sum = Calculator.Add(5, 3);
Console.WriteLine(sum); // Выведет 8


🟠Свойства
Статические свойства похожи на статические поля, но с доступом через методы get и set.
public class Configuration
{
private static string _setting;

public static string Setting
{
get { return _setting; }
set { _setting = value; }
}
}

// Доступ к статическому свойству
Configuration.Setting = "My Setting";
Console.WriteLine(Configuration.Setting); // Выведет "My Setting"


🟠Конструкторы
Статические конструкторы используются для инициализации статических членов класса. Они вызываются один раз при первом обращении к статическим членам.
public class Database
{
public static string ConnectionString;

static Database()
{
ConnectionString = "Initial Catalog=myDatabase;Data Source=myServer;";
}
}

// При первом доступе вызывается статический конструктор
Console.WriteLine(Database.ConnectionString); // Выведет строку подключения


🚩Зачем нужен?

🟠Общие данные и функции:
Статические члены полезны для хранения данных или функций, которые должны быть общими для всех экземпляров класса.
🟠Упрощение доступа:
Позволяет вызывать методы и свойства без необходимости создавать экземпляр класса.
🟠Инициализация ресурсов:
Статические конструкторы полезны для инициализации ресурсов или настройки параметров, необходимых для работы класса.

🚩Ограничения

🟠Статические методы не могут обращаться к нестатическим членам напрямую, так как у них нет доступа к экземпляру класса.
🟠Статические конструкторы не могут иметь параметры и вызываются автоматически при первом обращении к классу.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Зачем нужен Git?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥1👾1
🤔 Как понять, что в коде будет использоваться Iquerable, а не IEnumerable?

Это интерфейсы, которые используются для работы с коллекциями данных, но они имеют разные цели и применяются в разных сценариях. Разница между ними лежит в подходе к выполнению запросов и обработке данных. Вот ключевые отличия и рекомендации по выбору между IEnumerable и IQueryable.

🚩IEnumerable

🟠Выполнение на стороне клиента
Все операции выполняются на стороне клиента, то есть данные уже загружены в память. Подходит для работы с коллекциями, которые уже загружены в память (например, массивы, списки).

🟠Методы расширения LINQ
Методы LINQ, такие как Where, Select и другие, применяются к объекту IEnumerable и выполняются на стороне клиента. Каждый метод LINQ создает новую коллекцию, что может привести к повышенным затратам памяти и времени выполнения.

🟠Ленивая загрузка (Lazy Loading)
Операции с IEnumerable выполняются лениво, т.е. элементы коллекции обрабатываются по мере их запроса.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Пример запроса LINQ с использованием IEnumerable
IEnumerable<int> evenNumbers = numbers.Where(n => n % 2 == 0);

foreach (int number in evenNumbers)
{
Console.WriteLine(number); // Выведет 2 и 4
}


🚩IQueryable

🟠Выполнение на стороне сервера
Запросы IQueryable передаются внешнему источнику данных (например, базе данных) для выполнения. Запросы преобразуются в выражения, которые могут быть выполнены на стороне сервера, что минимизирует объем данных, передаваемых в память.

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

🟠Отложенное выполнение (Deferred Execution)
Запросы IQueryable не выполняются сразу при их определении. Они выполняются только при итерации или вызове метода, который требует выполнения запроса (например, ToList, FirstOrDefault).

using System.Linq;
using System.Data.Entity; // Пример для Entity Framework

public class MyDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
}

public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

public class Program
{
public static void Main()
{
using (var context = new MyDbContext())
{
// Пример запроса LINQ с использованием IQueryable
IQueryable<Product> expensiveProducts = context.Products.Where(p => p.Price > 100);

foreach (Product product in expensiveProducts)
{
Console.WriteLine(product.Name);
}
}
}
}


🚩Как понять, что использовать

🟠Используйте `IEnumerable`, если
Коллекция уже загружена в память. Вы работаете с небольшими наборами данных. Не требуется выполнение запросов на стороне сервера.
🟠Используйте `IQueryable`, если
Вы выполняете запросы к базе данных или другому удаленному источнику данных. Требуется отложенное выполнение запросов для оптимизации выполнения. Нужно минимизировать объем данных, загружаемых в память, путем фильтрации на стороне сервера.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 С точки зрения контроля версий, каким образом обмениваться изменениями в базе данных?

1. Используются миграции для фиксации изменений структуры базы данных в виде кода.
2. С помощью систем контроля версий, таких как Git, изменения миграций синхронизируются между разработчиками.
3. Инструменты, такие как Flyway или Liquibase, автоматизируют применение миграций.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👀2👍1
🤔 Может ли абстрактный метод быть вне абстрактного класса?

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

🚩Почему абстрактный метод требует абстрактного класса?

Абстрактный метод — это метод, который объявлен, но не имеет реализации. Он выступает как "контракт", который обязан быть реализован в производном классе.
public abstract class Shape
{
public abstract double CalculateArea();
}


Абстрактные методы имеют следующие особенности:
Они не могут содержать тело (реализацию).
Их цель — заставить производные классы реализовать конкретную функциональность.
Они всегда принадлежат абстрактным классам.

🚩Пример ошибки

Если попытаться объявить абстрактный метод в обычном классе, компилятор выдаст ошибку
public class RegularClass
{
public abstract void SomeMethod(); // Ошибка: абстрактный метод может быть только в абстрактном классе
}


🚩Логика дизайна

C# требует, чтобы абстрактные методы находились только в абстрактных классах, потому что:
Абстрактные классы могут содержать как абстрактные, так и обычные методы. Это позволяет определять базовое поведение в абстрактном классе и оставлять специфическую реализацию производным классам.
Обычные классы не могут содержать абстрактные методы, так как они предназначены для создания объектов, а объект не может содержать "незавершённый" метод.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что такое partial классы?

Это способ разделения определения одного класса на несколько файлов.
1. Позволяют работать над одним классом нескольким разработчикам или генерировать часть кода автоматически.
2. Все части объединяются компилятором в единый класс.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
🤔 Про абстрактные классы, интерфейсы и в чем их разница и особенности?

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

🚩Абстрактный класс

Абстрактный класс — это класс, который не может быть создан напрямую (нельзя создать объект этого класса). Он может содержать как абстрактные методы (без реализации), так и методы с реализацией.
public abstract class Animal
{
public abstract void MakeSound(); // Абстрактный метод
public void Sleep() // Метод с реализацией
{
Console.WriteLine("Sleeping...");
}
}


Пример
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Bark!");
}
}


Использование
Animal myDog = new Dog();
myDog.MakeSound(); // Вывод: Bark!
myDog.Sleep(); // Вывод: Sleeping...


🚩Интерфейс

Интерфейс — это контракт, который определяет только сигнатуры методов, свойств, событий и индексаторов. Реализацию этих членов должен предоставить класс, который реализует интерфейс.
public interface IMovable
{
void Move();
int Speed { get; set; }
}


Пример
public class Car : IMovable
{
public int Speed { get; set; }

public void Move()
{
Console.WriteLine($"Moving at speed: {Speed}");
}
}


Использование
IMovable myCar = new Car { Speed = 60 };
myCar.Move(); // Вывод: Moving at speed: 60


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 Что такое partial методы?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
🤔 Что такое IQueryable?

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

🚩Как работает IQueryable

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

🟠Отложенное выполнение (Deferred Execution)
Запросы IQueryable не выполняются, пока не будут перечислены. Это позволяет системе строить более сложные запросы перед их выполнением.

🟠Составление запросов
Вы можете построить запрос по частям, добавляя условия на каждом шаге. Финальный запрос выполняется только при перечислении результатов, что позволяет избежать ненужной нагрузки на источник данных.

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

using (var context = new MyDbContext()) // MyDbContext — это контекст Entity Framework
{
IQueryable<Product> query = context.Products.Where(p => p.Price > 100);

// Запрос еще не выполнен, можно добавить другие условия
query = query.OrderBy(p => p.Name);

// Запрос выполняется только при перечислении
foreach (var product in query)
{
Console.WriteLine($"{product.Name}: {product.Price}");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 В чём разница между переопределением и сокрытием?

1. Переопределение: метод базового класса заменяется в производном с помощью override.
2. Сокрытие: метод базового класса скрывается с помощью ключевого слова new, но доступен через базовый класс.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое GVT?

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

🚩Global Virtual Time (Глобальное виртуальное время)

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

🟠Симуляторы дискретного времени
например, при моделировании сетей или физических систем.
🟠Алгоритмы для снятия состояния
Или управления памятью (garbage collection).

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

🚩Google Virtual Tables

В контексте баз данных и SQL, GVT может использоваться как обозначение для виртуальных таблиц, предоставляемых Google (например, в Google BigQuery).

Пример
Если вы работаете с Google BigQuery, виртуальные таблицы используются для создания временных представлений данных, которые могут быть обработаны SQL-запросами.

🚩Generic Virtualization Technology

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

🟠Серверы с виртуальными машинами
Которые требуют доступа к ускоренной графике.
🟠Облачные сервисы
Предоставляющие GPU как услугу.

Пример
Intel GVT-g — технология, которая позволяет нескольким виртуальным машинам совместно использовать один GPU, обеспечивая каждому виртуальному окружению необходимую производительность.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤯2😁1
🤔 В чём преимущество блока using?

1. Обеспечивает автоматическое освобождение ресурсов, таких как файлы или сетевые соединения, по завершении работы.
2. Упрощает управление ресурсами, минимизируя утечки памяти.
3. Гарантирует вызов метода Dispose, даже если возникло исключение.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
🤔 Какие методы есть в Action фильтре?

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

🚩Методы в Action фильтре

🟠OnActionExecuting
Этот метод вызывается перед выполнением метода действия. Здесь можно добавить логику, которая будет выполняться до вызова действия, например, логирование или проверка условий.
public void OnActionExecuting(ActionExecutingContext context)
{
// Логика до выполнения действия
}


🟠OnActionExecuted
Этот метод вызывается после выполнения метода действия. Здесь можно добавить логику, которая будет выполняться после вызова действия, например, логирование результатов или модификация ответа.
public void OnActionExecuted(ActionExecutedContext context)
{
// Логика после выполнения действия
}


🟠OnActionExecutionAsync
Этот метод объединяет функциональность OnActionExecuting и OnActionExecuted в одном асинхронном методе. Здесь можно определить логику, которая будет выполняться как до, так и после выполнения метода действия.
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Логика до выполнения действия

var resultContext = await next();

// Логика после выполнения действия
}


🚩Реализации Action фильтра

Синхронный Action фильтр:
public class SampleActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Логика до выполнения действия
Console.WriteLine("Before executing action");
}

public void OnActionExecuted(ActionExecutedContext context)
{
// Логика после выполнения действия
Console.WriteLine("After executing action");
}
}


Асинхронный Action фильтр:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Логика до выполнения действия
Console.WriteLine("Before executing action");

var resultContext = await next();

// Логика после выполнения действия
Console.WriteLine("After executing action");
}
}


🚩Применение Action фильтра

Action фильтр можно применять к контроллерам или действиям контроллера с помощью атрибута [ServiceFilter] или [TypeFilter]. Также его можно зарегистрировать глобально в Startup.cs.

Применение к контроллеру или действию:
[ServiceFilter(typeof(SampleActionFilter))]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}


Глобальная регистрация:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(config =>
{
config.Filters.Add(typeof(SampleActionFilter));
});
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое CD?

Это практика автоматической доставки изменений в продакшен или на тестовые серверы.
1. Continuous Delivery: подготовка изменений для выпуска, но развёртывание требует ручного подтверждения.
2. Continuous Deployment: изменения автоматически разворачиваются после успешного прохождения тестов.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Как в кучах разделяются объекты?

В .NET среде управления памятью, объекты размещаются в куче (heap), и управление памятью осуществляется сборщиком мусора (Garbage Collector, GC). Куча разделена на несколько поколений для оптимизации производительности управления памятью.

🚩Поколения кучи

Куча в .NET разделена на три поколения: Generation 0, Generation 1 и Generation 2. Это разделение позволяет эффективно управлять памятью, минимизируя частоту сборок мусора и оптимизируя их выполнение.

🟠Generation 0
Содержит новосозданные объекты. Сборка мусора для этого поколения происходит чаще, так как большинство объектов "умирает" быстро. Наименьший размер среди всех поколений.

🟠Generation 1
Промежуточное поколение, используемое для объектов, которые пережили хотя бы одну сборку мусора Generation 0. Содержит объекты с более длительным временем жизни, чем объекты в Generation 0.

🟠Generation 2
Содержит объекты с самым длительным временем жизни. Наибольший размер среди всех поколений. Сборка мусора для этого поколения происходит реже всего.

🚩Large Object Heap (LOH)

LOH используется для размещения крупных объектов (размером 85,000 байт и более). Объекты в LOH не перемещаются при сборке мусора, что уменьшает фрагментацию памяти. Сборка мусора для LOH происходит одновременно со сборкой Generation 2.

🚩Как разделяются объекты

🟠Размещение объектов
При создании объекта он сначала размещается в Generation 0. Если объект переживает сборку мусора в Generation 0, он перемещается в Generation 1. Если объект переживает сборку мусора в Generation 1, он перемещается в Generation 2.

🟠Сборка мусора
Generation 0: Быстрая и частая сборка. Цель - освободить память от краткоживущих объектов.
Generation 1: Реже, чем Generation 0. Служит промежуточной зоной.
Generation 2: Самая редкая и длительная сборка. Обрабатывает долгоживущие объекты.
Large Object Heap (LOH): Сборка мусора проводится вместе с Generation 2.

public class Program
{
public static void Main()
{
// Создание объектов в Generation 0
for (int i = 0; i < 1000; i++)
{
var obj = new object();
}

// Создание большого объекта (размещается в LOH)
byte[] largeArray = new byte[100000];

// Принудительный вызов сборщика мусора
GC.Collect();

// Проверка поколения объекта
Console.WriteLine(GC.GetGeneration(largeArray)); // Скорее всего, 2
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
🤔 В чем разница между Postgres и MySQL?

1. Postgres: поддерживает расширенные функции, такие как JSONB, сложные индексы, транзакции с ACID и CTE.
2. MySQL: быстрее на простых запросах, но ограничен в функциях для сложных операций.
3. Postgres больше подходит для аналитики, а MySQL — для высокопроизводительных веб-приложений.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10😁2