← Academy Blog

Марафон підготовки 2022

Translated into:

Стартував марафон підготовки до тестування Binary Studio Academy 2022! Щотижневі питання, відповіді та пояснення чекають на блозі.

  • [.NET] Який тип має повертати даний метод?
    public static {ReturnType} GetNums()
    {
        var number = 0;
        while (true)
        {
            if (number > 5)
                yield break;
            yield return number++;
        }
    }

    a) void
    b) IEnumerable<int>
    c) List<int>
    d) int
    e) object

    Розгорнути правильну відповідь з поясненням

    Наведений метод використовує два спеціальних ключових слова yield break та yield return. Метод, у якому використовуються такі конструкції, називається ітератором. Ітератор може бути іменованим (як у нашому випадку), так і не іменованим. Не іменований ітератор оголошується для класу за допомогою визначення методу GetEnumerator(). У цьому випадку єкземпляри такого класу можна напряму використовувати у foreach чи для linq операцій. Відмінність ітератора від звичайного метода полягає у тому, що метод повертає єдине значення за допомогою return, а ітератор – декілька (або взагалі жодного). Ітератор повернить стільки значень, скільки викликано yield return. Виклик yield return можно написати декілька разів поспіль або, як у завданні, використати цикл. Ключове слово yield break означає що більше елементів повертати не потрібно, навіть якщо далі слідують іще конструкції yield return. Зупинка ітератора з використанням yield break не є обов'язковою. Наприклад ми можемо переписати код із завдання так:

    while (number < 5)
    {
        yield return number++;
    }

    Також цікавим є перехоплення помилок у ітераторі. Ключове слово yield не можна використовувати всередині try-catch блоку. Натомість потрібно спочатку отримати значення для повернення, а вже потім викликати yield наприклад:

    foreach (var item in data)
    {
      try
      {
          result = PrepareData(item);
      }
      catch (Exception ex)
      {
          Console.Error.WriteLine(ex.Message);
          continue;
      }
      yield return result;
    }

    У попередньому абзаці вже згадувалося де можна використати результат, шо повертає ітератор – у конструкції foreach та для linq операцій. А отже значення, що повертає ітератор, має бути інтерфейсом IEnumerable. Типізація ж для IEnumerable має відповідати саме тому типу, що повертає yield return. У нашому випадку це IEnumerable<int>. Правильна відповідь: a) IEnumerable

  • [JS/Mobile] Що виведеться у консоль у цих двух випадках?

    a)

    for (var i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 1);
    }

    b)

    for (let i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 1);
    }

    a) a) 0 1 2 3 4; b) 5 5 5 5 5
    b) a) 5 5 5 5 5; b) 0 1 2 3 4
    c) a) 5 5 5 5 5; b) 5 5 5 5 5

    Розгорнути правильну відповідь з поясненням

    Для початку потрібно розібратися у чому різниця між var та let. Область видимості змінної, оголошеної через var, це її поточний контекст виконання. Який може обмежуватися функцією чи бути глобальним, для змінних, оголошених поза функцією. Але у var є одна слабкість. Розглянемо її на прикладі нижче.

    var greeting = 'say hi';
    var times = 4;
    
    if (times > 3) {
      var greeting = 'say Hello instead';
    }
    
    console.log(greeting); // "say Hello instead"

    Як видно, оскільки умова times > 3 повертає значення true, значення змінної greeter перевизначається як 'say Hello instead'. Якщо ви несвідомо використаєте greeting в інших ділянках коду, ви отримаєте непередбачуванний результат. Це може викликати безліч помилок у вашому коді. Ось чому виникає потреба в let та const.

    let має блокову область видимості. Блок – це фрагмент коду, обмежений фігурними дужками {}. Все, що знаходиться всередині фігурних дужок, відноситься до блоку. Таким чином, змінна, оголошена в блоці через let, буде доступна лише усередині цього блоку. Давайте тепер розглянемо ще один приклад.

    let times = 4;
    
    if (times > 3) {
      let greeting = 'say Hello';
      console.log(greeting); // "say Hello"
    }
    
    console.log(greeting); // ReferenceError: greeting is not defined

    З цього прикладу видно, що спроба використати greeting поза блоком (фігурних дужок, у межах яких змінна була визначена) поверне помилку, через те що let має блокову область видимості.

    Тож повернемося до завдання. Оскільки setTimeout виконується асинхронно, а одна мілісекунда це дуже довгий час для комп’ютера, то переданний колбек викличеться вже після виконання циклу.

    У випадку a змінна i оголошується за допомогою ключового слова var, тому вона є глобальною. Вона буде перезаписуватися кожну ітерацію, а коли викличеться setTimeout, буде мати своє останнє значення - 5, тож у консоль послідовно виведеться 5 5 5 5 5.

    У випадку b змінна i вже оголошена через let і має блокову область видимості. Тобто вона є доступною лише в області видимості циклу for. Під час кожної ітерації змінна матиме нове значення, а після виконання коду у консоль виведеться 0 1 2 3 4.

    Отже правильна відповідь a) 5 5 5 5 5; b) 0 1 2 3 4

  • [QA] Скільки тестів потрібно для досягнення 100% покриття рішень?
    function WhatIsGreater(a, b) {
      let result;
      if (a > b) {
        result = 'a is greater than b';
      }
      if (b > a) {
        result = 'a is less than b';
      } else {
        result = 'friendship :)';
      }
      return result;
    }

    a) Достатньо 1-го тесту
    b) Для повного покриття потрібно 2 тести
    c) Неможливо визначити необхідну кількість тестів через брак інформації
    d) Потрібно 3 тести

    Розгорнути правильну відповідь з поясненням

    To answer this question you need to know the basics of flowcharts. Flowcharts use special shapes to represent different types of actions or steps in a process.

    Process Code

    Завдяки блок-схемі ми зможемо наглядно побачити роботу нашого коду та проаналізувати скільки тестів потрібно для досягнення 100% покриття рішень (Decision/Branch coverage). Основна мета Decision/Branch coverage - охопити всі гілки хоча б один раз (true і false). Тобто потрібно знайти та покрити мінімальну кількість шляхів.

    Зображення нашого коду у вигляді блок-схеми:

    Our Code

    Таким чином, ми маємо 3 гілки, кількість тест кейсів для яких - 3:

    1. Перший - перевіряє що, якщо WhatIsGreater(2, 1), тоді в результаті виконання if (a > b) ми отримаємо 'a is greater than b'.
    2. Другий - дозволяє впевнитись що, якщо WhatIsGreater(1, 2), то программа пройде if (b > a), та в результаті буде 'a is less than b'.
    3. Третій тест кейс - перевіряє, що в інших випадках результат 'friendship :)'. Тобто, якщо параметри будуть однакові WhatIsGreater(2, 2), то отримаємо 'friendship :)'

    Для досягнення 100% покриття рішень нам потрібно 3 тест кейси.

  • [.NET] Виконання якого рядку призведе до помилки?
    namespace BSA2021
    {
      class Program
      {
        static void Main()
        {
          var array = new string[] { "Welcome", "to", "Binary", "Studio", "Academy" };
    
          var a = array[..0];
          var b = array[2..^0];
          var c = array[^0];
        }
      }
    }
    

    a) 9
    b) 10
    c) 11
    d) Помилок при виконанні не буде

    Розгорнути правильну відповідь з поясненням

    У завданні наведено невеличку програма, яка складається із масиву строк, а також із дій над цим масивом. Дії над масивом виконуються з використанням індексів та діапазонів. Розглянемо їх детальніше:

    Індекс вказує на порядкове місце деякого елемента у послідовності. Індекс можна вказувати або рахуючи від початку послідовності, або від її кінця. У першому випадку індекс першого елемента є 0, другого – 1, третього – 2, і так далі. Останній елемента має індекс array.Length - 1. Для відрахунку елемента від кінця послідовності використовується спеціальний оператор ^. Останній елемент матиме індекс ^1, передостанній – ^2, а перший – ^array.Length. Індекс, записаний як ^0, відповідатиме довжині масиву.

    Діапазон задає деяку частину послідовності, яка обмежена двома індексами. Для визначення діапазону призначено оператор .. . Індекс початку діапазону вказується лівіше оператора, а кінця – правіше. Елемент, із індексом що відповідає початку діапазона, включається у діапазон. А елемент із індексом кінця – ні. У діапазоні можно не вказувати індекс початку і кінця, тоді початковим індексом буде вважатися 0, а кінцевим ^0.

    Тепер розглянемо хід виконання програми. На сьомому рядку корректно створюється масив строк із п'яти елементів. На 9-му рядку беремо діапазон, який починається із першого елемента і закінчується цим же першим елементом, тобто змінна a буде містити порожній масив строк. На 10-му рядку беремо діапазон із третього до останнього елемента, тобто змінна b містит {"Binary", "Studio", "Academy" }. 11-й рядок має присвоєння змінній єдиного елемента, який знаходиться на позиції ^0, тобто на array.Length. Тут маємо помилку виконання IndexOutOfRangeException.

    Правильна відповідь: c) 11

  • [.NET] IDOR prevention tool (не бійтеся назви, сама задача весела)Weekly Challenge

    Вступ

    У кібербезпеці існує вразливість, яка називається insecure direct object reference (IDOR). Простіше кажучи, це коли у користувача є можливість отримати доступ до даних, до яких він насправді не має доступу. Зазвичай це відбувається, коли програма показує ідентифікатори внутрішніх об’єктів у простій формі. Наприклад, https://medium.com/@elon/posts/82048f77 або навіть https://medium.com/@elon/posts/1.

    Уявімо, що це ваша публікація за цим посиланням. Якщо ви достатньо допитливі, ви, ймовірно, заміните деякі значення в GUID або підставите «2» замість «1», щоб побачити, що станеться.

    З іншого боку, може бути такий ендпоінт: https://medium.com/@elon/posts/PII6xnIiNeyv. У цьому випадку ви не знаєте, яке значення використовувати замість цього довгого ідентифікатора, щоб попитати щастя.

    Але як програміст ви можете припустити, що це не просто випадкові літери та цифри. І будете праві. Насправді, це зашифроване значення GUID.

    Завдання

    Створіть просту програму (Web API), щоб інтегрувати це шифрування/дешифрування. Використовуйте такі класи:

    Модель:

    public class Resource
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }

    Сервіс:

    public class ResourceService
    {
        private static readonly List<Resource> Resources = new();
    
        public Guid Add(string name)
        {
            var resource = new Resource
            {
                Id = Guid.NewGuid(),
                Name = name
            };
    
            Resources.Add(resource);
            return resource.Id;
        }
    
        public Resource Get(Guid id)
        {
            var resource = Resources.FirstOrDefault(x => x.Id == id);
            return resource;
        }
    }

    Контролер:

    [Route("api/[controller]")]
    [ApiController]
    public class ResourcesController : ControllerBase
    {
        private ResourceService _resourceService;
    
        public ResourcesController()
        {
            _resourceService = new ResourceService();
        }
    
        [HttpGet("{id}")]
        public Resource Get(Guid id)
        {
            return _resourceService.Get(id);
        }
    
        [HttpPost]
        public Guid Post([FromBody] string name)
        {
            return _resourceService.Add(name);
        }
    }

    Якщо ви створите просту програму ASP.NET Core Web API і використаєте ці класи, у вас буде 2 ендпоінти для додавання та отримання ресурсу. Основна загвоздка полягає в тому, що вам потрібно оновити код, щоб відповідати наступним вимогам:

    • Коли ви створюєте новий ресурс, вам потрібно отримувати ідентифікатор цього щойно створеного ресурсу в зашифрованому вигляді (не як GUID):
      • POST-запит: /api/resource з тілом: My new resource
      • Відповідь: PII6xnIiNeyv-Vxy
    • Коли ви отримуєте ресурс за його ідентифікатором, вам потрібно передавати його в зашифрованому вигляді
      • GET-запит: /api/resource/PII6xnIiNeyv-Vxy
      • Відповідь:
    {
      "id": "82048f77-9995-4287-bc0d-471ca3c394b3",
      "name": "My new resource"
    }

    Існує кілька способів виконати це завдання:

    1. Найпростіший та очевидний (шифрування та дешифрування в кожному контролері)
    2. Використання ASP.NET Core middleware
    3. Використання ASP.NET Core filters
    4. Custom JSON converters
    5. Напевно є й інші

    Деякі з них можуть здатися складними, тому намагайтеся рухатися один за іншим. Це гарна нагода дізнатися багато нового про корисні особливості ASP.NET Core.

    Можете використовувати будь-який вид шифрування.

    Розгорнути правильну відповідь з поясненням
  • [JS/Mobile] Що виведе цей код?
    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b());
    console.log(obj.с());

    a) 1 1
    b) undefined undefined
    c) 1 undefined
    d) null null

    Розгорнути правильну відповідь з поясненням

    Перед тим, як розібрати цей приклад, ми повинні зрозуміти, що таке точка виклику, контекст та стрілочна функція.

    Точка виклику — це місце в коді, де була викликана функція (не там, де вона оголошена). Ми повинні досліджувати точку виклику, щоб відповісти на запитання: на що ж вказує this?

    Загалом пошук точки виклику виглядає так: "знайти звідки викликається функція", але це не завжди так легко, оскільки певні шаблони кодування можуть ввести в оману щодо справжньої точки виклику.

    Важливо поміркувати над стеком викликів (стеком функцій, які були викликані, щоб привести нас до поточної точки виконання коду). Точка виклику, яка нас цікавить, знаходиться у виклику перед поточною виконуваною функцією.

    Контекст виконання (execution context) — це концепція, що описує оточення, у якому виконується код. Код завжди виконується всередині якогось контексту

    Стрілочна функція (arrow function) — це, простий і лаконічний синтаксис для створення функцій, який часто краще ніж звичайний Function Expression

    Простими словами

    let func = (arg1, arg2, ...argN) => expression;

    те саме, що й

    let func = function (arg1, arg2, ...argN) {
      return expression;
    };

    Проте крім синтаксису написання є також важливі відмінності про які ми поговоримо пізніше, але все по черзі.

    Тепер розглянемо як точка виклику впливає на те, що буде у this під час виконання функції.

    Взагалі існує 4 правила прив’язки для цього:

    • прив’язка за замовчуванням;
    • неявна прив’язка
    • явна прив’язка
    • жорстка прив’язка

    У нашому прикладі ми розглядаємо неявну прив’язку. Розберімо наступний код:

    function foo() {
      console.log(this.a);
    }
    
    var obj = {
      a: 2,
      foo: foo,
    };
    
    obj.foo(); // 2

    По-перше, відзначимо спосіб, яким була оголошена функція foo(), а потім пізніше додана як посилання в obj. Незалежно від того чи була foo() спочатку оголошена в obj або додана пізніше як посилання (як у наведеному вище коді), ні в тому, ні в іншому випадку функція насправді не "міститься" в об'єкті obj.

    Однак, точка виклику використовує контекст obj, щоб посилатися на функцію, тому можна сказати, що об'єкт obj "володіє" або "містить" посилання на функцію в момент виклику функції.

    Яку назву ви б не вибрали для цього шаблону, коли викликається foo(), їй передує об'єктне посилання на obj. Коли є об'єкт контексту для посилання на функцію, правило неявної прив'язки говорить про те, що саме цей об'єкт і слід використовувати для прив'язки this до виклику функції.

    Оскільки obj є this для виклику foo(), this.a – синонім obj.a.

    Виходячи з цього можемо дати відповідь на першу частину нашого завдання

    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b()); // 1

    Як ви гадаєте чи отримаємо ми той самий результат, коли напишемо console.log(obj.c());? Якщо ваша відповідь ні — то ви цілком праві.

    Справа у контексті. На відміну від інших функцій, стрілочні функції не мають власного контексту. На практиці це означає, що вони наслідують сутності this та arguments від батьківських функцій. У анонімної функції b() є власний контекст, який вона перехоплює у obj. А у c() стрілочна функція запам’ятала свій контекст у момент створення і відповідно при виклику цієї функції вона буде посилатися на нього. Таким чином ми отримуємо window.

    Однак ви можете поставити запитання «Але чому в момент створення контексту було window, а не об'єкт, всередині якого вона була оголошена як метод?». Стрілочна функція в момент створення шукає найближчий до неї контекст і запам'ятовує його, а він у нас такий самий як і у разі простого присвоєння всередині obj.

    Підсумовуючи усе, що написано вище виділимо дві основних тези.

    Теза 1 Для функцій, оголошених через function f( ) { }, this обчислюється в момент виклику і дорівнює об'єкту перед точкою. Якщо такого об'єкта немає — тоді this буде вказувати на глобальний контекст (window). Проте це не стосується суворого (strict) виконання.

    Теза 2 Для стрілочних функцій this визначається в момент їх створення і більше ніколи не змінюється

    Отже, правильна відповідь:

    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b()); // 1
    console.log(obj.с()); // undefined
  • [JS/Mobile] ГалереяWeekly Challenge

    Імплементнути логіку, яка дасть змогу при кліку на слайд робити його активним(додавати клас active).

    Slider

    Source Code

    Розгорнути правильну відповідь з поясненням
  • [QA] Одна із частин роботи QA - тестування вимог. Проаналізуйте вимоги нижче. Як вважаєте, що з ними не так?
    1. Система повинна бути зручною та доступною.
    2. Має бути спосіб аутентифікації.
    3. Необхідно створити систему підтримки з чатом, контактною формою та допомогою для авторизованих користувачів.
    4. Неавторизований користувач може скористатись чатом та контактною формою.
    5. Студент увійде до системи, вказавши своє ім'я користувача або/та емейл, пароль та іншу відповідну інформацію.
    6. Час завантаження кожної сторінки мусить бути прийнятним.
    Розгорнути правильну відповідь з поясненням

    Погано написані вимоги створюють ризик, що розробник, QA, PO та кінцевий користувач можуть очікувати від функціоналу відмінних характеристик.

    Під час тестування вимог ми мусим звертати увагу на:

    • однозначність вимог та їх повноту - кожен повинен розуміти вимоги однаково;
    • несуперечливість;
    • необхідність вимог та можливість їх реалізації;
    • можливість перевірки встановлених вимоги після їх реалізації.
    1. Система повинна бути зручною та доступною.

    Зручний для кого та що означає доступний? Вимозі бракує чіткості та однозначності. Різні люди по різному сприймають та тлумачать ці слова.

    1. Має бути спосіб аутентифікації.

    В цьому випадку також не зрозуміло який спосіб аутентифікації повинен бути - електронна пошта та пароль, надсилання тимчасового коду на адресу електронної пошти чи одноразового пароля по SMS. Варіанти є різні. Вимоги повинні бути однозначними. Також важливо бути впевненим, що вимоги дійсно необхідні та їх можливо реалізувати.

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

    Уявіть, скільки у цьому випадку може бути варіантів та завдань? Підтримка онлайн-чату, підтримка по телефону, цілодобова підтримка електронною поштою, сторінки довідки на веб-сайті… Вимоги повинні відображати функціональність, дійсно необхідну для користувача. Переконайтеся, що вимоги по суті чіткі та короткі, але в той же в змозі передати всю потребу.

    1. Неавторизований користувач може скористатись чатом та контактною формою.

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

    1. Студент увійде до системи, вказавши своє ім'я користувача або/та емейл, пароль та іншу відповідну інформацію.

    Під “іншій необхідній інформації” замовник, розробник та тестувальник може мати на увазі різне. Як вже було згадано, один з критеріїв хорошої документації - однозначність - однакове сприйняття вимог всіма членами команд, ніяких розбіжностей в трактуванні бути не повинно.

    1. Час завантаження кожної сторінки мусить бути прийнятним.

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

    Крім того, сторінка повинна завантажуватись у прийнятні терміни, а які прийнятні терміни? Прийнятні для кого?

    Необхідно уточнити, які сторінки маються на увазі «сторінки реєстрації студента та зарахування на курс», а також вказати прийнятний часовий інтервал, наприклад, 5 секунд.

  • [QA] В БД є таблиця Contact, де зберігаються: ім`я користувача, дата народження та місто, де користувач проживає.Weekly Challenge

    QA Table

    Завдання цього тижня:

    • Вивести ім'я (Name) та дату народження (BirthDate) всіх контактів (табл. Contact), у яких в імені друга літера "a". Вибірку відсортувати за зменшенням дати народження (BirthDate).
    • У таблиці Contact у контакта Lena змінити значення: BirthDate = 1987-10-08 та UsrCityLiving = Харків.
    • До таблиці Contact додати новий контакт: Name = Alex, BirthDate = 1986-10-08, UsrCityLiving = Київ.
    Розгорнути правильну відповідь з поясненням
  • [.NET] Яким буде результат виконання цього коду?
    class Program
    {
        static void Main(string[] args)
        {
            First first = new Second("some item");
            First another = new Third();
        }
    }
    class First
    {
        public First()
        {
            Console.WriteLine("First created");
        }
    }
    class Second : First
    {
        private Second()
        {
            Console.WriteLine("Second created");
        }
        public Second(string item)
        {
            Console.WriteLine("Second created with Item: {0}",  item);
        }
    }
    class Third : Second
    {
        public Third()
        {
            Console.WriteLine("Third created");
        }
    }

    a) First createdSecond created with Item: some itemFirst createdThird created
    b) Виникне помилка компіляції
    c) Second created with Item: some itemThird created
    d) Виникне помилка виконання

    Розгорнути правильну відповідь з поясненням

    Наведенні у завданні програма побудована із трьох класів та із виклику конструктора цих класів у Main(). Для класів використовується механізм успадкування і побудовано наступну ієрархію: від базового класу First успадковується клас Second в якого, в свою чергу, є нащадок – клас Third. Коли ми створюємо екземпляр класу, у якого є батьківський клас, спочатку викликається конструктор батьківського класу. За замовчуванням для батьківського класу буде викликано конструктор без параметрів. Для явного виклику потрібного конструктора призначено ключове слово base().

    Клас First має єдиний конструктор без параметрів, який виводить у консоль строку "First created".

    Клас Second має два конструктора. Один із них без параметрів і виводить строку "Second created", а також його рівень доступу визначено як private, а отже він доступний для виклику лише “всередині” цього класу. Інший конструктор має параметр item та друкує повідомлення "Second created with Item: {0}". Обидва ці конструктора неявно викликають конструктор First().

    Клас Third має єдиний конструктор без параметрів, який друкує "Third created" в консолі. Але, оскільки відсутній явний виклик батіківського констуктора з параметрамами, буде здійснено виклик приватного констуктора Second(). Це призведе до помилки під час компіляції CS0122.

    Правильна відповідь: b) Виникне помилка компіляції

  • [.NET] Створити Web API додаток із статичною in-memory базою даних (тобто ви маєте один екземпляр бази на весь додаток) розміром у 20 елементів максимум. Елемент повинен мати наступні поля - Id (унікальне), Name та CreationDate. Всі інші поля на ваш розсуд.Weekly Challenge

    Додаток має надавати доступ до наступних можливостей:

    1. Оновлення елемента у базі за Id.
    2. Додавання елемента у базу. Треба враховувати, що максимальний розмір списку - 20 елементів.
    3. Отримання нової структури даних яка складається з двох списків і поля з датою. Структура будується наступним чином: користувач передає дату на ендпоінт і по цій даті ми розбиваємо наш список на два - елементи, створені до вказаної дати і після. У полі з датою повертаємо передану дату.
    4. Видалення елемента зі списку за Id.
    Розгорнути правильну відповідь з поясненням
  • [JS/Mobile] Чому буде дорівнювати змінна someVariable?
    function func() {
      return this;
    }
    
    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };
    
    const target = outerObj.innerObj;
    const someVariable = target.method();

    a) window
    b) outerObj
    c) innerObj
    d) undefined

    Розгорнути правильну відповідь з поясненням

    Для того, щоб дати правильну відповідь на це запитання, нам необхідно хоча б трохи знати як працює ключове слово this в JavaScript, тому зараз ми це коротко розглянемо.

    Що таке this?

    Як правило, метод об'єкта потребує доступу до інформації, яка зберігається в об'єкті, щоб виконати з нею будь-які дії (відповідно до призначення методу).

    Наприклад, коду всередині user.sayHi() може знадобитися ім'я користувача, яке зберігається в об'єкті user.

    Для доступу до інформації всередині об'єкта метод може використовувати ключове слово this.

    Наприклад:

    const user = {
      name: 'Tanya',
      sayHi: function () {
        return this.name;
      },
    };
    
    user.sayHi(); // 'Tanya'

    Тут під час виконання коду user.sayHi() значенням this буде user (посилання на об'єкт user).

    Використання this дозволяє створювати універсальні функції, які б корректно працювали у якості методів для різних об’єктів. У цьому сила this - значення цього ключового слова обчислюється під час виконання коду і залежить від контексту.

    Зрозуміти, чому дорівнює this у тому чи іншому випадку досить просто: this - це об’єкт перед точкою. Наприклад, при виклику obj.f() значення this всередині f дорівнює obj.

    function sayHi() {
      console.log(this.name);
    }
    
    const user = {
      name: 'Tanya',
    };
    
    const admin = {
      name: 'Misha',
    };
    
    user.f = sayHi;
    admin.f = sayHi;
    
    // виклики функції, наведені нижче, мають різне значення this
    // "this" всередині функції є посиланням на об'єкт, який вказано "перед точкою"
    user.f(); // Tanya (this == user)
    admin.f(); // Misha (this == admin)
    
    admin['f'](); // Misha (неважливий спосіб доступу до методу – через точку або квадратні дужки)

    Якщо ж ми викличемо функцію без об’єкта перед точкою, то отримаємо undefined (якщо працюємо у режимі "use strict"), або глобальний об’єкт (якщо режим "use strict" не активовано). У браузерному середовищі глобальний об’єкт - це об’єкт window.

    function sayHi() {
      console.log(this);
    }
    
    sayHi(); // undefined або глобальний об’єкт

    Є ще деякі способи явно вказати функції, який саме об’єкт вона має вважати за this під час свого виконання. Для цього використовуються методи call, apply та bind.

    Тепер перейдемо до завдання

    З самого початку ми маємо функцію func яка просто повертає this. Ми вже знаємо, що this може бути різним і його значення буде залежати від того, як ми викличемо цю функцію.

    function func() {
      return this;
    }

    Далі ми створюємо об’єкт, у якого є вкладений об’єкт всередині. І вже цьому вкладеному об’єкту ми додаємо нашу функцію як метод.

    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };

    Вкладений об’єкт - це повністю повноправний об’єкт як і будь який інший, він також може мати свої методи і властивості. Наш код міг би виглядати і так:

    const innerObj = {
      value: 20,
      method: func,
    };
    
    const outerObj = {
      value: 10,
      innerObj: innerObj,
    };

    Далі ми створюємо нову змінну target і вказуємо, що вона дорівнює нашому вкладеному об’єкту. Добре, тепер в нас є 2 змінні, які вказують на один і той самий вкладений об’єкт.

    const target = outerObj.innerObj;

    Тобто в нашому випадку target - це той самий innerObj, а не його копія. Просто тепер в нас 2 шляхи до його властивостей та методів - outerObj.innerObj та target. Подивіться уважно на цей код, якщо не дуже розумієте про що йде мова:

    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };
    
    const target = outerObj.innerObj;
    
    target.value = 0;
    console.log(outerObj.innerObj.value); // 0
    // тому що target - просто посилання на той самий об'єкт innerObj, а не його копія

    Добре, з цим розібрались, що в нас далі?

    const someVariable = target.method();

    А далі ми просто викликаємо target.method(), де method - це наша функція func яка повертає this. this дорівнює об’єкту перед точкою, у цьому випадку об’єкт перед точкою - це target. Але, як ми вище зрозуміли, target та innerObj - це не просто два однакових об’єкти або дві копії - це один і той самий об’єкт. Тому в нас someVariable, target та outerObj.innerObj - це все посилання до одного об’єкта у пам’яті.

    Правильна відповідь - innerObj.

  • [JS/Mobile] Створити випадаючий блок з іконками додатків як в ГуглаWeekly Challenge

    Google Bar

    Головні етапи виконання завдання:

    • зробити кнопку, яка буде відкривати/закривати блок з додатками;
    • зробити сам блок з іконками додатків;
    • реалізувати кастомний скроллбар для цього блоку;
    • допилити стилі щоб виглядало усе як в оригіналі.

    Чим меньше ваша кнопка та блок відрізняються від оригинального - тим крутіше вам вдалося виконати завдання! В ідеалі вони можуть бути взагалі ідентичні, з усіма стилями та hover-еффектами. Але якщо вам вдастся виконати лише частину з цих завдань - це вже буде дуже корисно для вас!

    Що можна і треба робити для виконання завдання:

    • поклацати цю менюшку в Гуглі, подивитися як вона працює;
    • використати dev-tools, щоб заглянути всередину - що як зроблено, як виставляються зображення для елементів меню, як картинки звідти або навіть шматочки CSS можна перевикористати для виконання завдання;
    • гуглити - як зробити кастомний чекбокс, як зробити кастомний скроллбар і усе інше що вам буде потрібно;
    • використовувати тільки HTML, CSS та картинки.

    Чого НЕ треба робити:

    • не використовувати JS чи будь-які CSS бібліотеки.

    Ви можете спробувати виконати це завдання з нуля, або використати ось цю заготовку, де вже є:

    • загальна розмітка та стилі;
    • сам блок з іконками додатків;

    У таком разі треба буде лише:

    • зробити кнопку, яка буде відкривати/закривати блок з додатками;
    • доробити позиціонування блоку та щоб він реагував на кнопку;
    • додати кастомний скроллбар для цього блоку;
    • додати hover, focus стилі для кнопки.
    Розгорнути правильну відповідь з поясненням
  • [QA] Що таке верифікація?
    1. Перевірка, що програмне забезпечення реалізоване у відповідності із дизайном.
    2. Перевірка, що програмне забезпечення задовольняє вимоги та очікування замовника.
    3. Перевірка, що програмне забезпечення задовольняє вимоги та очікування користувачів.
    4. Перевірка, що програмне забезпечення реалізоване у відповідності з очікуваними вимогами.
    Розгорнути правильну відповідь з поясненням

    Давайте пригадаємо що таке Verification та Validation.

    Verification. Відповідає на запитання “Функціональність працює відповідно до вимог?”. Verification - процес оцінки системи і її компонентів з метою співставлення результатів поточного етапу розробки, початково сформованим умовам. Тобто, виконання заданих завдань, цілей, строків по розробці продукту та відповідність стандартам.

    Validation. Відповідає на запитання: “Чи очікуємо ми того, що очікує користувач?”. При процесі валідації переконуємось, що розроблене програмне забезпечення відповідає визначеним бізнес-вимогам та потребам користувачів.

    Таким чином, правильна відповідь - Перевірка, що програмне забезпечення реалізоване у відповідності з очікуваними вимогами.

  • [QA] На цьому тижні ми попрактикуємось у визначенні пріоритетів для тест кейсів. Терміни завершення тестування часто жорсткі. В таких випадках є ризик пропустити тестування деяких важливих функцій. Тому варто визначати пріоритет кожного тесту під час його документування.Weekly Challenge

    Об’єкт:

    Інтернет-магазин

    Статус:

    На етапі розробки, але вже готові: головна сторінка з товарами; каталог з категоріями товарів; картки для кожного товару з фото (з можливістю zoom); сторінки товару; пошук по товарам; фільтри (ціна, виробник); сортування за ціною; кошик з можливостями змінити кількість товару, видалити товар; сторінка оформлення замовлення; інтеграція з платіжною системою, надсилання на електронну скриньку листа з деталями замовлення.

    Вимоги замовника:

    • Користувач повинен бачити на головній сторінці інтернет-магазину акційні товари.
    • Прев’ю картки товару повинно містити:
      • фото
      • ціну
      • кнопку “У кошик”
    • Після натискання на картку, відкривається сторінка товару з:
      • описом
      • ціною
      • фото
      • можливістю додати товар у кошик.
    • У кошику користувач повинен мати змогу:
      • видалити товар
      • змінити його кількість
      • мати кнопку “Оформити замовлення”.
    • На сторінці оформлення замовлення повинні бути вибір типу оплати:
      • онлайн оплата карткою
      • накладений платіж
      • та один тип доставки - забрати у відділенні пошти.
    • Також на сторінці оформлення повинні бути наступні елементи:
      • поле “Email”
      • поле “Номер телефону”
      • кнопка “Придбати”.
    • Якщо користувач вибрав оплату карткою, то після натиску на кнопку “Придбати” система переадресовує його на сторінку оплати, де потрібно ввести дані банківської картки.
    • Після оформлення замовлення на електронну скриньку користувача повинен прийти лист з деталями замовлення.

    Для замовника важливо, щоб користувач міг мати можливість принаймні замовити товар.

    Класифікація визначення пріоритету тесту, якою ми будем користуватися:

    • Високий (High): Тести охоплюють критичну функцію програми, схильні до дефектів модулі та модулі, в які були внесені нещодавні зміни.
    • Середній (Medium): Тести включають негативні тестові сценарії. До цієї категорії включені перевірки полів, тестові приклади генерації повідомлень про помилки.
    • Низький (Low): Тести охоплюють функціональність програми, що залишилася (включаючи користувальницький інтерфейс і менш схильні до дефектів модулі).

    Розставте пріоритет наступним перевіркам:

    1. Відображення акційних товарів на головній сторінці.
    2. Відображення відповідної категорії товарів на сторінці вибраної категорії з каталогу товарів.
    3. Сортування за ціною.
    4. Відображення відповідних товарів на екрані користувача після пошуку.
    5. Фільтрація по ціні, виробнику.
    6. Можливість збільшити/зменшити фото у картці товара.
    7. Відображення опису товара, ціни.
    8. Додавання товара у кошик, видалення товара з кошику.
    9. Відповідність ціни товара у кошику тій, що зазначена у картці.
    10. Валідація полів “Email” та “Номер телефону” на сторінці оформлення замовлення.
    11. Перехід до сторінки онлайн оплати карткою.
    12. Перехід з кошика до сторінки оформлення замовлення після натискання на кнопку “Оформити замовлення”.
    13. Надходження на електронну скриньку листа з деталями замовлення на пошту після успішного замовлення товару та наявність у листі інформації про деталі замовлення.
    Розгорнути правильну відповідь з поясненням
  • [.NET] Що виведе цей код?
    namespace BSA2022
    {
        struct Point
        {
            public int X;
            public int Y;
        }
    
        class Program
        {
            static void Main()
            {
                CreatePoint(out Point point);
                ResetPoint(in point);
                IncreasePoint(ref point);
    
                Console.WriteLine($"({point.X};{point.Y})");
            }
    
            static void ResetPoint(in Point point)
            {
                point.X = 1;
                point.Y = 1;
            }
    
            static void CreatePoint(out Point point)
            {
                point.X = 2;
                point.Y = 2;
            }
    
            static void IncreasePoint(ref Point point)
            {
                point.X *= 3;
                point.Y *= 3;
            }
        }
    }

    a) (3;3)
    b) (6;6)
    c) (0;0)
    d) Буде помилка при виконанні
    e) Буде помилка при компіляції

    Розгорнути правильну відповідь з поясненням

    Розглянемо із чого “складається” програма наведена у питанні. Вона побудована з простої структури та визові трьох методів для виконання дій над цією структурою. Складність полягає у тому, що структура, подібно до int, зберігається у стеці та є типом-значення. А також що у методах дій над структурою використовуються ключові слова (in, ref, out) що слугують модифікаторами параметрів. Без використання цих модифікаторів до метода завжди передається нова копія даних змінної, які зберігаються у стеці. Розглянемо детально ці модифікатори:

    Ключове слово ref вказує на те, що аргумент передається за посиланням, а не за значенням. Тобто будь-яка зміна значення цього аргументу всередині метода призведе до зміни відповідного аргумента з яким було викликано метод. Також використання цього ключового слова вимагає того, щоб змінна була ініціалізована перед її використанням як параметр, інакше буде помилка компіляції CS0165.

    Ключове слово out також вказує що аргумент передається за посиланням. Такий аргумент називається “вихідним параметром” метода і, на відміну від ref, не вимагає попередньої ініціалізації параметра. Натомість всередині метода аргумент має бути обов'язково ініціалізовано всередині цього методу, інакше виникає помилка компіляції CS0177.

    In – визначає параметр який передається за посиланням, однак всередині метода його заборонено змінювати. Таке ключове слово зазвичай використовується при необхідності передачі великих за обсягом пам’яті структур всередину метода. При спробі змінити такий параметр виникає помилка компіляції CS8332 – неможливість змінити readonly змінну. Також зберігається необхідність попередньої ініціалізації змінної, що передається як параметр.

    А тепер проаналізуємо виклик кожного методу із Main(). Першим йде виклик CreatePoint(). Його параметр позначено як out, а отже накладається умова на ініціалізацію всередині методу. Структура вважається ініціалізовано коли ініціалізовано всі її поля – отже помилок немає, і point має значення (2;2). Наступним йде виклик ResetPoint() із параметром in. Всередині метода виконується присвоєння цьому параметру, а отже маємо помилку компіляції CS0165.

    Правильна відповідь: e) помилка компіляції .

  • [.NET] КалькуляторWeekly Challenge

    Створіть калькулятор, який можна використовувати так:

    var result = 5.Add(10).MultiplyBy(2);
    // or
    result = new Calculator(5).Add(10).MultiplyBy(2).Equals();
    
    Console.WriteLine(result); // 30

    Код може виглядати трохи інакше залежно від реалізації, але основна ідея полягає в тому, щоб використовувати методи для виконання операцій у ланцюжковий спосіб (тобто виклики мають іти один за одним).

    • Реалізуйте 4 основні методи (сигнатури опущено для гнучкості ваших рішень):
      • Add()
      • Subtract()
      • MultiplyBy()
      • DivideBy()
    • Не соромтеся додавати складніші методи, щоби зробити калькулятор більш функціональним

    Існує принаймні 2 способи вирішення цього завдання. Але радимо спробувати й інші. Використовуйте підказки, якщо застрягли:

    • Перша підказка Цей спосіб передбачає «розширення» 😉 функціональності відомих типів
    • Друга підказка А цей — занурення в тему патерн дизайну (особливо тих, що стосуються будівельних матеріалів 🏗️

    Не соромтеся придумувати власні підходи.

    Не забувайте, що ми створюємо програмне забезпечення для звичайних користувачів, які можуть робити помилки: замість чисел вводити звичайний текст, ділити на 0 і так далі. Дозвольте користувачам використовувати не тільки цілі числа, а й числа з плаваючою точкою. Намагайтеся обробляти якомога більше edge cases, щоби зромити додаток більш стабільним.

    Розгорнути правильну відповідь з поясненням
  • [JS/Mobile] Який рядок пропущенно?

    Юний програміст займався рефакторингом коду. Він вирішив обгорнути функцію сторонньої бібліотеки, що приймає колбек, у проміс, проте зробів помилку. Вкажіть, який рядок пропущенно:

    // before
    someFunc((err, res) => {
      if (err) {
        console.log(err);
      } else {
        console.log(res);
      }
    });
    
    // after
    1 const someFuncPromise = () =>
    2   new Promise((resolve, reject) => {
    3     //
    4     someFunc((err, res) => {
    5       if (err) {
    6         console.log('Error');
    7         //
    8       }
    9       resolve(res);
    10      console.log('Sucess');
    11      //
    12    });
    13  });

    a) return cb() - 7-ий рядок
    b) if - 3-ий рядок
    c) return reject(err) - 7-ий рядок
    d) else - 7-ий рядок
    e) return - 11-ий рядок

    Розгорнути правильну відповідь з поясненням

    Щоб розв’язати це завдання, по-перше, потрібно розібратися як повинен працювати колбек переданний в функцію сторонньої бібліотеки. Він приймає два параметри err та res, потім іде if блок, який перевіряє чи є умова істинною. У JavaScript усі значення є істинними, якщо вони не визначені як хибні. Тобто усі значення, окрім false, 0, "", null, undefined і NaN істинні. Тож у нашому випадку якщо ми отримаємо помилку, то вона виведеться в консоль. Якщо ж помилки немає, то виконання перейде до блоку else і тоді в консоль виведеться значення res.

    Під час рефакторингу функція була обгорнута у проміс, який має прийняти наприкінці виконання один зі станів: fulfilled (за допомогою виклику resolve()) або rejected (за допомогою reject()).

    Розглянемо детальніше виконання цього коду.

    • Якщо у нас немає помилки, то перша умова if (err) поверне false і тоді виконання перейде до наступного блоку і виконається resolve промісу і залогується console.log('Sucess') .
    • У випадку помилки умова if (err) поверне true. Через це у консоль виведеться "Error" , але на виконання фунції це ніяк не вплине — проміс благополучно зарезолвиться та спрацює “успішний” console.log.

    Отже, по-перше, нам слід дотриматись логіки роботи з промісами та викликати reject(err)  у разі помилки.

    А по-друге, слід не забувати, що функції resolve та reject змінюють стан проміса, але не зупиняють його, через це у консоль все одно виведеться повідомлення "Success".

    Отож повна правильна видповідь тут буде така: return reject(err) - 7-ий рядок.

  • [JS/Mobile] Пошуку персонажів Гри престолів v2Weekly Challenge

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

    • Наразі треба надати користувачам можливість обирати улюблених персонажів.
    • Також для більш пріємного користувацького інтерфейсу давайте додамо лоадер на час завантаження даних про персонажів.

    Стартер проекту ви знайдете тут.

    Розгорнути правильну відповідь з поясненням
  • [QA] Retesting чи Regression?

    Поміркуйте та дайте відповідь, які з цих тверджень відносяться до Retesting, а які до Regression:

    1. Мета цього теста полягає в тому, щоб переконатися, що додавання свіжого коду, удосконалення або виправлення помилок не спричиняє нестабільності чи компрометації функціональності програмного забезпечення.
    2. Під час цього тестування тестувальники перевіряють, що всі тестові випадки, які виявилися невдалими під час останнього виконання, пройшли після усунення дефектів.
    3. Це тестування не включає перевірку дефектів.
    4. Цей тип тестування гарантує, що зміни в коді не вплинуть на функціональність системи.
    5. Це тестування можливо автоматизувати.
    6. Цей тип тестування проводиться після усунення дефектів.
    7. Тестові випадки, які загалом провалилися, піддаються такому типу тестування.
    8. Тестові випадки, які проходять у загальному порядку, піддаються такому типу тестування.
    Розгорнути правильну відповідь з поясненням

    Retesting - вид тестування, під час якого перевіряють, що всі тестові випадки, які виявилися невдалими під час останнього виконання, пройшли після усунення дефектів.

    Regression testing - мета цього тестування переконатися, що програма продовжує працювати належним чином після змін коду, оновлення або удосконалення. Не включає перевірку дефектів. Регресійне тестування відповідає за загальну стабільність і функціональність наявних функцій. Регресійне тестування можливо автоматизувати, оскільки мануально воно займає багато часу.

  • [QA] Цього тижня завдання полягає у пошуку багів та створенні баг-репортів. На скрині зображена проста логін-форма. Користувач відкрив сайт перейшов до логін-форми, не ввів електронну адресу, але ввів пароль. Також переглянув відповідність символів паролю, натиснувши на іконку “Show”, а потім - скрив пароль. Weekly Challenge

    Знайдіть баги логін-форми на цьому скрині та оформіть їх у вигляді баг-репортів.

    Register form

    Розгорнути правильну відповідь з поясненням
  • [.NET] Який із блоків catch буде задіяний у результаті виконання коду?
    static void Recursive()
    {
        Recursive();
    }
    
    try
    {
        Recursive();
    }
    catch (InsufficientMemoryException)
    {
        // block 1
        throw;
    }
    catch (OutOfMemoryException)
    {
        // block 2
        throw;
    }
    catch (StackOverflowException)
    {
        // block 3
        throw;
    }
    catch (Exception)
    {
        // block 4
        throw;
    }

    a) block 1
    b) block 2
    c) block 3
    d) block 4
    e) жодного блоку не буде задіяно

    Розгорнути правильну відповідь з поясненням

    Насамперед пригадаємо як працює конструкція try…catch при наявності декількох блоків catch: при виникненні виключення виконується послідовне, починаючи згори, порівняння типу аргументу блоку catch із типом об’єкту помилки. І якщо тип аргументу співпадає із типом помилки, або ж якщо є серед базових типів класу помилки – виконується блок catch. Наступні ж блоки ігноруються. До речі, у catch блоках тип аргументу не може повторюватися. Конструкції throw в середні catch призводять до того, що помилка ”передається на рівень вище”, і навіть якщо після поточного блоку catch є інший блок, який може перехопити цю помилку за її типом, він не буде виконаний.

    Тепер проаналізуємо для яких виключень призначений кожен блок:

    InsufficientMemoryException – виключення свідчить що при перевірці доступної пам’яті виявилось шо її недостатньо. Це виключення виникає лише при явному використанні об’єкту MemoryFailPoint. Є похідний типом від OutOfMemoryException.

    OutOfMemoryException – повідомляє по для продовження виконання програми недостатньо пам’яті. Виключення виникає, або при перевищенні максимального значення довжини для StringBuilder, або коли CLR не може виділити достатню неперервну кількість пам’яті для виконання операції (створення об’єкту, виклик методу, тощо). Ця помилка пов’язана із пам’яттю купи.

    StackOverflowException – виникає при переповненні стека виконання, оскільки він містить занадто багато вкладених викликів методів. Якщо ця помилка не викинута явно (через throw), то вона не може бути перехоплена у try…catch.

    Exception – базовий тип для всіх винятків. Використовується для оголошення catch для будь-якої помилки.

    А тепер розглянемо що відбувається у блоці try: виконується виклик методу Recursive(). Цей метод не використовує MemoryFailPoint та не створює і не модифікує об’єкти, а отже блоки 1 та 2 не будуть задіяні. Натомість метод продукує неконтрольовану рекурсію, а отже буде переповнено стек і буде виключення StackOverflowException, яке згенеровано системою. Отже блоки 3 та 4 також не будуть задіяні.

    Правильна відповідь: e) жодного блоку не буде задіяно.

  • [.NET] В рамках цього weekly challenge вам треба створити веб API з in-memory базою даних, в якій буде 20 елементів (тобто список даних створений безпосередньо в самій програмі).Weekly Challenge

    Кожен елемент цього списку повинен мати поля з ім'ям (Name) та датою створення (CreationDate). Всі інші поля на ваш розсуд. Веб API має надавати користувачу можливість отримати наступні набори даних:

    1. Отримати перші 5 елементів відсортованих за ім'ям в алфавітному порядку
    2. Отримати перші 5 елементів відсортованих за датою створення у спадаючому порядку
    3. Отримати всі елементи з ім'ям довшим за 5 літер

    P.S. Ви вільні використовувати будь-які бібліотеки що можуть допомогти вам створити правдоподібні дані для вашого списку або ви можете створити ці дані за тематикою у якій ви зацікавлені, вибір за вами. P.P.S Для тестування вашої програми можна використати, наприклад, Postman. Відчуття, коли власноруч створений ендпоінт отримує перший запит, ви запам'ятаєте надовго.

    Розгорнути правильну відповідь з поясненням
  • [JS/Mobile] Скільки одиниць виведеться в консоль?
    const func = (x) => {
      switch (isNaN(x) || x) {
        case null: {
          console.log(1);
          break;
        }
        case undefined: {
          console.log(1);
        }
        case NaN: {
          console.log(1);
          return;
        }
        case false: {
          console.log(1);
        }
        case true: {
          console.log(1);
        }
        default:
          break;
      }
    };
    
    func();

    a) 1
    b) 2
    c) 3
    d) 4

    Розгорнути правильну відповідь з поясненням

    Для того, щоб правильно відповісти на це питання необхідно розуміти як працювати з оператором switch, як передаються параметри функції а також як працюють функція isNaN та оператор або (||).

    Спочатку варто зрозуміти яке ж значення буде в параметрі x. Оскільки при виклику функції не було передано жодних параметрів то буде використано значення за замовчуванням - undefined. Це можна легко перевірити виконавши наступний шматок коду.

    const f = (arg) => console.log(arg === undefined);
    
    f();

    Далі, варто розуміти як працює оператор switch. Цей оператор оцінює значення яке йому надається, та виконує код пов'язаний з відповідним case та, що важливо пам'ятати, з усіма наступними конструкціями. У цьому можна легко переконатись виконавши наступний код:

    switch (2) {
      case 1:
        console.log('1');
      case 2:
        console.log('2');
      case 3:
        console.log('3');
      default:
        console.log('default');
    }

    Таким чином у консоль буде виведено:

    2
    3
    default

    У javascript є 3 механізми, які зупиняють виконання усіх case конструкцій, це: break, return, throw.

    • break - зупинить виконання усіх наступних case конструкцій, і продовжить виконання функції.
    • return - зупинить виконання усіх наступних case конструкцій, і поверне значення з функції.
    • throw - зупинить виконання усіх case конструкцій і кине помилку.

    Так, якшо ми перепишемо код вище з використанням break ми отримаємо зовсім інший результат:

    switch (2) {
      case 1:
        console.log('1');
        break;
      case 2:
        console.log('2');
        break;
      case 3:
        console.log('3');
        break;
      default:
        console.log('default');
    }

    Буде виведено тільки одна цифра:

    2

    Наступним важливим кроком для розв'язання задачі має бути визначення значення, яке поверне функція isNaN. Щоб це зрозуміти спершу необхідно розібратись, що таке NaN. NaN - пердставляє значення яке не вдалось перетворити у число (Not-a-Number), такі випадки можуть траплятись коли:

    • Конвертується значення, яке не може бути презентовано числом, у число (Number('foo'))
    • Виконується матемтична операція результатом якої не є реальне число (Math.sqrt(-1))
    • Оператором математичної операції є NaN (7 * NaN)
    • Результат виразу є невизначеним (0 * Infinity)
    • Будь-яка операція, яка включає строку і не є операцією додавання ('foo' / 5)

    Функція isNaN конвертує передане в неї значення у число і перевіряє чи це значення є NaN.

    console.log(isNaN('55')); // false
    console.log(isNaN(undefined)); // true

    Останнє, що потрібно знати для розв'язання цієї задачі це поведінку оператора або - ||. Цей оператор повертає друге значення лише тоді коли переше - falsy.

    console.log(false || 'shown'); // 'shown'
    console.log(true || 'not shown'); // true

    Повертаючись до задачі, ми можемо сказати що у функції параметр x має значення undefined. Оскільки це значення не може бути конвертованим у число, то функція isNaN поверне true. Отже оператор || теж поверне true оскільки це значення є правдивим. А це означає, що виконається констркуція

        case true: {
          console.log(1);
        }

    а оскільки немає жодного оператора який би зупиняв виконання case конструкцій, то також виконається і default(Хоча він нічого не виводить у даному завданні). Отже у консоль буде виведено:

    1

    Правильна відповідь - 1.

  • [JS/Mobile] Завданням для цього тижня буде зробити додаток для пошуку персонажів Гри престолів.Weekly Challenge

    Дані про персонажів будемо брати з цього API.

    View Example Example

    Щоб спростити вам завдання ми підготували заготовку де вже майже все готово, залишилося зробити отримання персонажів з API. Клонуйте репозиторій із заготовкою і читайте опис.

    Розгорнути правильну відповідь з поясненням
  • [QA] Під час тестування застосунку для здорового харчування було виявлено 200 критичних багів за перші 20 спринтів. За наступні 20 спринтів без зміни QA команди та підходу то тестування було знайдено 25 критичних багів, проте клієнти почали скаржитись на різні дефекти, які вони знаходили під час користування новими версіями. Який з принципів тестування наглядно спостерігається у наведеному прикладі?

    a) Повне тестування неможливе
    b) Парадокс пестициду
    c) Тестування залежить від контексту
    d) Відсутність помилок оманлива
    e) Користувачі завжди скаржаться

    Розгорнути правильну відповідь з поясненням

    Давайте пригадаємо 7 принципів тестування

    Тестування показує наявність дефектів, а не їх відсутність

    Процес тестування не підтверджує, що будь-яке програмне забезпечення повністю коректне і повністю позбавлене проблем. Тестування допомагає значно зменшити кількість не виявлених дефектів, що ховаються в програмному забезпеченні, але пошук і вирішення цих проблем сам по собі не є доказом того, що програмне забезпечення або система на 100% без проблем.

    Вичерпне тестування неможливе

    Як би нам не хотілося вірити чи бажати, щоб це було правдою(!), протестувати ВСЕ – усі комбінації вхідних даних та передумов абсолютно неможливо. Для найпростішого функціоналу це реальніше, але таке тестування було б дуже не ефективним та надзвичайно коштовним.

    Раннє тестування економить час і гроші

    Тут все просто. Чим менше стадій розробки живе баг, тим дешевший він є для проекту. Найдешевший баг це баг, знайдений на стадії ідеї, найдорожчий - знайдений кінцевим користувачем.

    Дефекти групуються разом

    Найбільша кількість багів зазвичай зосереджена в кількох проблемних модулях програми

    Тестування залежить від контексту

    Контест використання застосунку буде визначати типи та види тестування. До прикладу cloud версія застосунку потребує тестування навантаження від тисяч користувачів, а от standalone версія, яка встановлюється користувачем у себе на комп’ютері - ні.

    Відсутність помилок є оманою

    Якщо ваше програмне забезпечення або система непридатні (або не відповідають бажанням користувачів), то не має значення, скільки дефектів знайдено та виправлено – вони все одно непридатні. Тож у цьому сенсі не має значення, наскільки ваша система без проблем чи без помилок; якщо зручність використання настільки погана, що користувачі не можуть орієнтуватися, або/і вона не відповідає вимогам бізнесу, то вона зазнала невдачі, незважаючи на те, що мало помилок.

    Парадокс пестициду

    Це засновано на теорії про те, що коли ви багаторазово використовуєте пестициди на посівах, комахи в кінцевому підсумку виробляють імунітет, що робить його неефективним. Подібно до тестування, якщо одні й ті самі тести виконуються безперервно, тоді – хоча вони можуть підтвердити, що програмне забезпечення працює – врешті-решт вони не зможуть знайти нові проблеми. Важливо продовжувати переглядати свої тести та змінювати або доповнювати свої сценарії, щоб запобігти появі парадоксу пестицидів – можливо, паралельно використовуючи різні методи тестування, методи та підходи.

    Вірна відповідь - парадокс пестициду :)

  • [QA] Завдання цього тижня орієнтоване на те щоб потренувати свої QA skills та вирішити досить просту, на перший погляд, задачу. Наша задача протестувати ліфт в багатоповерховому будинку з офісними приміщеннями. Всього в будинку 10 поверхів. Ліфт має вантажопідйомність до 500 кг.Weekly Challenge

    Підказка: очікуємо побачити застосування різних видів тестування.

    Розгорнути правильну відповідь з поясненням