Ответы пользователя по тегу ASP.NET
  • Я сделал Code Review, может быть я где-то ошибся или у вас есть что добавить?

    @nikifovadim Автор вопроса
    Software Engineer
    Перво наперво напишу, всем спасибо за Ваши ответы!) В общем, по хорошему стоило бы мне учесть все ответы разработчиков на habr и моих друзей. Но я решил пока запостить вот такой ответ на свой вопрос.

    Можно было бы добавить в этот код еще документацию и что-то еще. Типо так ...
    /// <summary>
        /// Project status
        /// </summary>
        public enum ProjectStatus
        {
            NotStarted,
            Active,
            Completed
        }


    Может быть и расписать параметр и методы, что они возвращают или принимают. Как-то вот так ...
    /// <summary>
            /// Get project by id
            /// </summary>
            /// <param name="id">Id of project</param>
            /// <param name="cancellationToken"></param>
            /// <returns><see cref="ProjectResponse"/></returns>
            [HttpGet]
            [Route("projects/{id}")]
            [ProducesResponseType(typeof(ProjectResponse), 200)]
            [ProducesResponseType(400)]
            [ProducesResponseType(500)]
            public async Task<ProjectResponse> GetProject(long id, CancellationToken cancellationToken)
            {
                return await _projectService.GetByIdAsync(id, cancellationToken);
            }


    Не совсем хороший пример документации так, как например можно было бы подробнее расписать что он возвращает. Ну как Microsoft делает))) Весь код выше был показан только как пример)))

    Собственно вот как мне объяснил или показал мой наставник, как наверное стоило бы сделать по хорошему. Мне нужно еще самому этот код позапускать и все проверить / посмотреть, но сделаю это я после прогулки :) Может быть за это время у кого-то появиться какая-нибудь критика, вопросы, предложения и прочие :)
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using System.Threading;
     
    //EXTERNAL CODE
    //Приведен только для справки, никак нельзя менять, код обфусцирован, исходников нет
    public sealed class DataProvider : IDisposable
    {
        public int LongRunningCalculation(int value, int value2) 
        { 
            Thread.Sleep(200); // milliseconds
            if ((value + value2) % 3 == 0) // 1 of 3 throws exceptions
                throw new ArgumentNullException();
            else
             return value + value2; 
        }
        public void Dispose() { }
    }
    public class Calculator : IDisposable
    {
        private readonly Range rangeI = 0..10;
        private readonly Range rangeJ = 1..10;
     
        private readonly IDataProvider dataProvider;
     
        private readonly ConcurrentDictionary<Key, int> results = new();
     
        private readonly ConcurrentDictionary<Key, Exception> exceptions = new();
     
        public Calculator(DataProvider externProvider)
        {
            dataProvider = new CustomProvider(externProvider);
        }
     
        public async Task Calculate() /// async!!!
        {
            var tasks = new ConcurrentBag<Task>();
     
            for (var i = 0; i < rangeI.End.Value - rangeI.Start.Value; i++)
                for (var j = 0; j < rangeJ.End.Value - rangeJ.Start.Value; j++)
                {
                    var key = new Key(i, j);
                    tasks.Add(Task.Run(async () =>
                    {
                        try //try-get
                        {
                            var result = await dataProvider.LongRunningCalculationAsync(key.FirstValue, key.SecondValue);
                            results.TryAdd(key, result);
                        }
                        catch (Exception ex) // try-get
                        {
                            exceptions.TryAdd(key, ex);
                        }
                    }));
                }
     
            await Task.WhenAll(tasks);
        }
     
        public int GetValue(int first, int second)
        {
            if (results.TryGetValue(new Key(first, second), out int value))
            {
                return value;
            }
            else
            {
                if(exceptions.TryGetValue(new Key(first, second), out Exception ex))
                    throw ex;
            }
            return 0;
        }
     
        public void Dispose() // обязательно реализовать
        {
            if (dataProvider != null) // проверка на null
                dataProvider.Dispose();
        }
    }
     
    public interface IDataProvider : IDisposable
    {
        Task<int> LongRunningCalculationAsync(int firstValue, int secondValue);
    }
     
    public class CustomProvider : IDataProvider
    {
        private readonly DataProvider _provider;
     
        public CustomProvider(DataProvider provider)
        {
            _provider = provider;
        }
     
        public void Dispose()
        {
            if (_provider != null)
                _provider.Dispose();
        }
     
        public Task<int> LongRunningCalculationAsync(int firstValue, int secondValue)
        {
            var tsc = new TaskCompletionSource<int>();
     
            Task.Run(() =>
            {
                try
                {
                    var result = _provider.LongRunningCalculation(firstValue, secondValue);
                    tsc.SetResult(result);
                }
                catch (Exception e)
                {
                    tsc.SetException(e);
                }
            });
     
            return tsc.Task;
     
            // no, because Exception
            return Task.Run(() => _provider.LongRunningCalculation(firstValue, secondValue));
        }
    }
     
    readonly public struct Key // struct immutable
    {
        public readonly int FirstValue;
        public readonly int SecondValue;
     
        public Key(int first, int second)
        {
            FirstValue = first;
            SecondValue = second;
        }
     
        public override int GetHashCode() // override !!!
        {
            return (FirstValue.GetHashCode() * 1_000_000 + SecondValue.GetHashCode()) % 1_000_000_000;
        }
     
        public override bool Equals(object obj) // override !!!
        {
            var other = (Key)obj;
            return GetHashCode() == other.GetHashCode();
        }
     
        public override string ToString() // не обязательно, но поскольку у нас ключи закрытые - сделаем
        {
            return FirstValue.ToString() + " " + SecondValue.ToString();
        }
    }
    
    
    class Program
    {
        static void Main(string[] args)
        {
            using var calculator = new Calculator(new DataProvider());
            calculator.Calculate().Wait();
            try
            {
                var r = calculator.GetValue(1, 1);
                Console.WriteLine("1: 1: " + r);
                r = calculator.GetValue(1, 2);
                Console.WriteLine("1: 1: " + r);
                r = calculator.GetValue(1, 3);
                Console.WriteLine("1: 1: " + r);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }
    }


    Добавлю от себя, что будь это допустим не интервью, а реальный проект то Code Review наверное бы делал не один я, а много разработчиков (команда). Ну после интервью я показав этот код своим друзьям, своему наставнику и выложив его на habr. Так же Code Review, как писали уже выше нужно делать в несколько подходов и добавлю от себя что его должен делать не один человек, что бы найти все возможные проблемы. В общем я соглашусь с мнением Александр то что компания возможно "галера" и добавлю что интервью прошло не так хорошо, мы договаривались на 2ч, а на деле оказалось 1ч с чем-то плюс мину. Только их HR / рекрутер показалась мне компетентной и она мне понравилось, а интервью г**** :)
    Ответ написан