# 🀝 Руководство для участников Бпасибо Π·Π° интСрСс ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ YandexMusic! Π­Ρ‚ΠΎΡ‚ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ содСрТит Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ для Ρ‚Π΅Ρ…, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ внСсти свой Π²ΠΊΠ»Π°Π΄ Π² Ρ€Π°Π·Π²ΠΈΡ‚ΠΈΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. ## πŸ“‹ Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅ - [КодСкс повСдСния](#кодСкс-повСдСния) - [Как Π½Π°Ρ‡Π°Ρ‚ΡŒ](#ΠΊΠ°ΠΊ-Π½Π°Ρ‡Π°Ρ‚ΡŒ) - [ΠŸΡ€ΠΎΡ†Π΅ΡΡ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ](#процСсс-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ) - [Π‘Ρ‚Π°Π½Π΄Π°Ρ€Ρ‚Ρ‹ ΠΊΠΎΠ΄Π°](#стандарты-ΠΊΠΎΠ΄Π°) - [Commit сообщСния](#commit-сообщСния) - [Pull Requests](#pull-requests) - [ΠžΡ‚Ρ‡Ρ‘Ρ‚Ρ‹ ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…](#ΠΎΡ‚Ρ‡Ρ‘Ρ‚Ρ‹-ΠΎΠ±-ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…) - [ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΏΠΎ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡΠΌ](#прСдлоТСния-ΠΏΠΎ-ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡΠΌ) ## 🀐 КодСкс повСдСния - Π‘ΡƒΠ΄ΡŒΡ‚Π΅ ΡƒΠ²Π°ΠΆΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ ΠΊ Π΄Ρ€ΡƒΠ³ΠΈΠΌ участникам - НС допускайтС Π΄ΠΈΡΠΊΡ€ΠΈΠΌΠΈΠ½Π°Ρ†ΠΈΡŽ, оскорблСния ΠΈ Π²Ρ€Π°ΠΆΠ΄Π΅Π±Π½ΠΎΠ³ΠΎ повСдСния - ΠšΡ€ΠΈΡ‚ΠΈΠΊΡƒΠΉΡ‚Π΅ ΠΈΠ΄Π΅ΠΈ, Π° Π½Π΅ людСй - Π Π΅ΡˆΠ°ΠΉΡ‚Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Ρ‹ конструктивно ## πŸš€ Как Π½Π°Ρ‡Π°Ρ‚ΡŒ ### 1. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° окруТСния ```bash # ΠšΠ»ΠΎΠ½ΠΈΡ€ΡƒΠ΅ΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ git clone https://git.frigat.duckdns.org/FrigaT/YandexMusic.git cd YandexMusic # Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ Π²Π΅Ρ‚ΠΊΡƒ для своСй Ρ€Π°Π±ΠΎΡ‚Ρ‹ git checkout -b feature/my-feature # ВосстанавливаСм зависимости dotnet restore # Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ dotnet build ``` ### 2. Установка инструмСнтов - **Visual Studio 2026 Enterprise** (рСкомСндуСтся) - **Visual Studio Code** + C# extension (Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π°) - **.NET 10 SDK** ### 3. Запуск тСстов ```bash dotnet test ``` ## πŸ”„ ΠŸΡ€ΠΎΡ†Π΅ΡΡ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ### Workflow ``` 1. Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ issue ΠΈΠ»ΠΈ создайтС Π½ΠΎΠ²Ρ‹ΠΉ 2. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ feature-Π²Π΅Ρ‚ΠΊΡƒ 3. ВнСситС измСнСния 4. ΠΠ°ΠΏΠΈΡˆΠΈΡ‚Π΅/ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ тСсты 5. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ΄ собираСтся ΠΈ тСсты проходят 6. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Pull Request 7. Π–Π΄ΠΈΡ‚Π΅ review 8. Π˜ΡΠΏΡ€Π°Π²ΡŒΡ‚Π΅ замСчания Ссли Π½ΡƒΠΆΠ½ΠΎ 9. Merge Π² master ``` ### ВСрсионированиС Π²Π΅Ρ‚ΠΎΠΊ ``` master β†’ Production вСрсия β”œβ”€β”€ feature/* β†’ НовыС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ β”œβ”€β”€ bugfix/* β†’ Π˜ΡΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΡ ошибок β”œβ”€β”€ refactor/* β†’ Π Π΅Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΈΠ½Π³ ΠΊΠΎΠ΄Π° └── docs/* β†’ ОбновлСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ``` ## πŸ“ Π‘Ρ‚Π°Π½Π΄Π°Ρ€Ρ‚Ρ‹ ΠΊΠΎΠ΄Π° ### ΠžΠ±Ρ‰ΠΈΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»Π° - **Π―Π·Ρ‹ΠΊ:** C# 12 - **ΠŸΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°:** .NET 10 - **Π‘Ρ‚ΠΈΠ»ΡŒ:** Microsoft C# Coding Conventions - **ДокумСнтация:** ВсС ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Π΅ Ρ‡Π»Π΅Π½Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ XML Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ Π½Π° русском ### ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° ```csharp namespace YandexMusic.API.API; /// API для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с альбомами. public class YAlbumAPI : YCommonAPI { /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр. /// ЭкзСмпляр основного API. public YAlbumAPI(YandexMusicApi yandex) : base(yandex) { } /// ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎΠ± альбомС ΠΏΠΎ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ. /// Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ альбома /// МодСль альбома ΠΈΠ»ΠΈ null Ссли Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ /// Если albumId null public async Task GetAlbumAsync(string albumId) { ArgumentNullException.ThrowIfNull(albumId); // РСализация return await Task.FromResult(null); } } ``` ### ΠŸΡ€Π°Π²ΠΈΠ»Π° имСнования ```csharp // ΠšΠ»Π°ΡΡΡ‹: PascalCase public class YandexMusicApi { } // ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹: PascalCase с Async суффиксом для асинхронных public async Task GetTrackAsync(string trackId) { } // Бвойства: PascalCase public YandexMusicApi Api { get; } // ΠŸΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹Π΅ поля: _camelCase private readonly HttpClient _httpClient; // ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹: camelCase public void DoSomething(string userName, int userId) { } // Π›ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅: camelCase var trackList = new List(); ``` ### Code Style Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ `.editorconfig` для автоматичСского форматирования: ```ini # ΠžΡ‚ΡΡ‚ΡƒΠΏΡ‹ - 4 ΠΏΡ€ΠΎΠ±Π΅Π»Π° indent_size = 4 # Новая строка для Ρ„ΠΈΠ³ΡƒΡ€Π½Ρ‹Ρ… скобок csharp_new_line_before_open_brace = all # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ var Π³Π΄Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ csharp_style_var_for_built_in_types = true # Null-forgiving operator с ΠΎΡΡ‚ΠΎΡ€ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ csharp_style_null_forgiving_operator = false ``` ### Nullable Reference Types ВсСгда Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ `enable`. ΠŸΡ€Π°Π²ΠΈΠ»Π°: ```csharp // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - явно ΡƒΠΊΠ°Π·Π°Π½ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ null public string? GetUserName() { } // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - явно Π½Π΅ null public string GetTitle() => "Title"; // ❌ ΠŸΠ»ΠΎΡ…ΠΎ - нСявная nullable ссылка public object GetSomething() { } // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ null-coalescing var result = value ?? defaultValue; // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ null-conditional var count = list?.Count ?? 0; ``` ### АсинхронноС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ```csharp // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - async/await public async Task GetTrackAsync(string id) { return await api.Track.GetTrackAsync(id); } // ❌ ΠŸΠ»ΠΎΡ…ΠΎ - Task.Result Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΠΎΡ‚ΠΎΠΊ public YTrack? GetTrack(string id) { return api.Track.GetTrackAsync(id).Result; } // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ - ConfigureAwait(false) Π² Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ… public async Task GetTrackAsync(string id) { return await api.Track.GetTrackAsync(id).ConfigureAwait(false); } ``` ### ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок ```csharp // βœ… Π₯ΠΎΡ€ΠΎΡˆΠΎ public async Task GetTrackAsync(string trackId) { ArgumentNullException.ThrowIfNull(trackId); ArgumentException.ThrowIfNullOrWhiteSpace(trackId); try { return await _provider.GetTrackAsync(trackId); } catch (HttpRequestException ex) { Logger.LogError(ex, "Ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Ρ‚Ρ€Π΅ΠΊΠ°"); throw; } } // ❌ ΠŸΠ»ΠΎΡ…ΠΎ - ΠΌΠΎΠ»Ρ‡Π° ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΡƒΠ΅ΠΌ ошибки public async Task GetTrackAsync(string trackId) { try { return await _provider.GetTrackAsync(trackId); } catch { } return null; } ``` ### Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° Ρ„Π°ΠΉΠ»Π° ```csharp using System; using System.Collections.Generic; using System.Threading.Tasks; namespace YandexMusic.API.API; /// API для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Ρ‚Ρ€Π΅ΠΊΠ°ΠΌΠΈ. public class YTrackAPI : YCommonAPI { /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр. public YTrackAPI(YandexMusicApi yandex) : base(yandex) { } /// ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Ρ‚Ρ€Π΅ΠΊ. public async Task GetTrackAsync(string trackId) { // рСализация } /// ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ нСсколько Ρ‚Ρ€Π΅ΠΊΠΎΠ². public async Task> GetTracksAsync(IEnumerable trackIds) { // рСализация } } ``` ## πŸ“ Commit сообщСния ### Π€ΠΎΡ€ΠΌΠ°Ρ‚ ``` ():