7
\$\begingroup\$

This past week, I had a coding interview where I have failed badly. The feedback that I get from the recruiter was that my code reminded the team of older ways of coding in C#. This led them to believe that I haven’t had much experience with newer version of the framework.

This made me quite confused as I literally don't know exactly what should I change so that my code could look more modern.

Was it about performance? Was my way of solving did not make use of the best practices? Any help will be greatly appreciated.

First of all, here is the problem. enter image description here enter image description here

enter image description here

enter image description here

enter image description here

As for the file of orders, it looks like this:

{
    "order-001": {
        "destination" : "YYZ"
    },
    "order-002": {
        "destination" : "YYZ"
    },
    "order-003": {
        "destination" : "YYZ"
    },
    "order-004": {
        "destination" : "YYZ"
    },
...
}

Instead of creating a big constant file for the schedules, I have decided to read them from a JSON file that I've filled using the scenario above.

{
    "1": {
        "departure": "YUL",
        "arrival": "YYZ",
        "day": 1
    },
    "2": {
        "departure": "YUL",
        "arrival": "YYC",
        "day": 1
    },
    "3": {
        "departure": "YUL",
        "arrival": "YVR",
        "day": 1
    },
    "4": {
        "departure": "YUL",
        "arrival": "YYZ",
        "day": 2
    },
    "5": {
        "departure": "YUL",
        "arrival": "YYC",
        "day": 2
    },
    "6": {
        "departure": "YUL",
        "arrival": "YVR",
        "day": 2
    }
}

Here is the code I have produced so that I can solve the problem:

First of all, I have a class called Loader which allows me to load all the elements of the JSON files into objects

Loader.cs

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Transport.ly
{
    public static class Loader
    {

        public static List<Order> LoadOrders()
        {

            List<Order> data;

            using (StreamReader r = new StreamReader(Constants.Path.JsonPath))
            {
                string json = r.ReadToEnd();
                data = JsonConvert.DeserializeObject<Dictionary<string, Order>>(json).Select(p => 
                new Order { Code = p.Key, Destination = p.Value.Destination, Priority = Int32.Parse( p.Key.Substring(p.Key.LastIndexOf('-') + 1))
            }).ToList();
            }

            return data;
        }

        public static Dictionary<int, Schedule> LoadScenarioSchedule()
        {

            Dictionary<int, Schedule> data;

            using (StreamReader r = new StreamReader(Constants.Path.ScenarioPath))
            {
                string json = r.ReadToEnd();
                data = JsonConvert.DeserializeObject<Dictionary<int, Schedule>>(json);
            }

            return data;
        }
    }
}

An order class

using System;
using System.Collections.Generic;
using System.Text;

namespace Transport.ly
{
    /// <summary>
    /// Represent an order
    /// </summary>
    public class Order
    {

        public Order()
        {
            _loaded = false;
        }

        public Order(string destination, string code, bool loaded, int priority)
        {
            _priority = priority;
            _loaded = loaded;
            _code = code;
            _destination = destination;
        }

        private string _destination;
        private string _code;
        private int _priority;
        private bool _loaded;

        public string Destination { get => _destination; set => _destination = value; }
        public string Code { get => _code; set => _code = value; }
        public bool Loaded { get => _loaded; set => _loaded = value; }
        public int Priority { get => _priority; set => _priority = value; }
    }
}

A class representing the schedules

using System;
using System.Collections.Generic;
using System.Text;

namespace Transport.ly
{
    /// <summary>
    /// Represent a schedule
    /// </summary>
    public class Schedule
    {

        public Schedule()
        {
            _loaded = false;
        }

        public Schedule(int day, string departure, string arrival)
        {

            _day = day;
            _departure = departure;
            _arrival = arrival;
        }

        private int _day;
        private string _departure;
        private string _arrival;
        private bool _loaded;

        public bool Loaded { get => _loaded; set => _loaded = value; }
        public string Arrival { get => _arrival; set => _arrival = value; }
        public string Departure { get => _departure; set => _departure = value; }
        public int Day { get => _day; set => _day = value; }
    }
}

A class that represent a flight

using System;
using System.Collections.Generic;
using System.Text;

namespace Transport.ly
{
    /// <summary>
    /// This class represent a flight
    /// </summary>
    public class Flight
    {

        public Flight()
        {
            _orders = new List<Order>();
        }

        public Flight(int number, Schedule schedule, List<Order> orders)
        {
            _orders = orders;
            _schedule = schedule;
            _number = number;
        }

        private int _number;
        private Schedule _schedule;
        private List<Order> _orders;

        public List<Order> Orders { get => _orders; }
        public Schedule Schedule { get => _schedule; }
        public int Number { get => _number; }
    }
}

Inventory.cs

using System.Collections.Generic;
using System.Linq;

namespace Transport.ly
{
    public class Inventory
    {
        public Inventory() {

            _schedules = new Dictionary<int, Schedule>();
            _orders = new List<Order>();
            _flights = new List<Flight>();

        }

        public Inventory(string name, Dictionary<int, Schedule> schedules, List<Order> orders)
        {
            _name = name;
            _schedules = schedules;
            _orders = orders;

            _flights = new List<Flight>();
        }

        public void LoadSchedule( int key) {

            _schedules[key].Loaded = true;
        }

        /// <summary>
        /// this function returns schedules that are loaded 
        /// </summary>
        /// <returns></returns>
        public Dictionary<int ,Schedule> GetLoadedSchedules() {

            return _schedules.Where(s => s.Value.Loaded)
                        .ToDictionary(dict => dict.Key, dict => dict.Value);
        }

        /// <summary>
        /// this function returns schedules that are not loaded yet
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, Schedule> GetAvailableSchedules()
        {
            return _schedules.Where(s => s.Value.Loaded == false)
                        .ToDictionary(dict => dict.Key, dict => dict.Value);
        }

        public List<Order> GetOrders() {

            return _orders;
        }

        public Dictionary<int, Schedule> GetSchedules()
        {
            return _schedules;
        }

        /// <summary>
        /// Generate Flight itineraries and return what hasbeen generate.
        /// This function return only orders that are loaded. In other words,
        /// Orders that have scedule. associated to them.
        /// </summary>
        /// <returns></returns>
        public List<Flight> GenerateFlights() {

            var loadedSchedules = GetLoadedSchedules();

            List<Schedule> sortedSchedule = new List<Schedule>();

            sortedSchedule = loadedSchedules.Values.ToList();

            sortedSchedule.Sort((emp1, emp2) => emp1.Day.CompareTo(emp2.Day));

            int flightNumber = 1;


            List<Order> ordersByPriority = _orders.OrderBy(o => o.Priority).ToList();


            foreach (Schedule schedule in sortedSchedule)
            {
                //if the schedule is already assigned to a flight, no need to add it
                if (_flights.Any(item => item.Schedule.Day == schedule.Day &&
                item.Schedule.Arrival == schedule.Arrival && item.Schedule.Departure == schedule.Departure))
                {
                    flightNumber++;
                    continue;
                }

                List<Order> orders = new List<Order>();

                //get 20 orders that has the same destination
                for (int i = 0; i < ordersByPriority.Count; i++)
                {
                    //Check if the order has the same destination as the scedule and if the order is not
                    //already loaded on a previous flights
                    if (schedule.Arrival == ordersByPriority[i].Destination && !ordersByPriority[i].Loaded)
                    {
                        orders.Add(ordersByPriority[i]);

                        ordersByPriority[i].Loaded = true;


                        if (orders.Count == Constants.Rule.PlaneBoxCountLimit)
                        {
                            break;
                        }
                    }
                }


                _flights.Add(new Flight(flightNumber, schedule, orders));

                flightNumber++;
            }

            return _flights;
        }

        private string _name;
        private List<Order> _orders;
        private Dictionary<int, Schedule> _schedules;
        private List<Flight> _flights;
    }








}

A class containing the srting constants

using System.IO;



namespace Transport.ly
{
    public static class Constants
    {
        public static class Messages
        {
            public const string ChooseDeparture = "Choose departure Location";
            public const string PressAnyKey = "\nPress any key to go to the main menu...";
            public const string QuiApplicationMenu = "[ 0 ] Quit application\n";
            public const string ReturnToMainMenu = "[ 0 ] Return to main menu\n";
            public const string Tryagain = "Try again!!";

        }

        public static class Header
        {
            public const string MainMenu = "========= Transport.ly ============";
            public const string ChooseScheduleToLoad = "========= Choose a schedule to Load ============";
            public const string LoadedSchedules = "=========Loaded schedules ============";
            public const string BatchOfOrders = "========= Bathch of Orders ===========";

        }

        public static class MenuOptions
        {
            public static readonly string[] MainMenu = { "1. Load a schedule", "2. List out the schedules", "3. Generate flight itineraries ",
            "5. Exit"};
        }

        public static class Path {

            public readonly static string JsonPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Files\\coding-assigment-orders.json");

            public readonly static string ScenarioPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Files\\scheduledFlights.json");
        }

        public static class Rule {

            public const int PlaneCount = 2;
            public const int DepartureHour = 12;
            public const int ArrivalHour = 0;
            public const int PlaneBoxCountLimit = 20;
        }
    }
}

And finaly the main

using System;
using System.Collections.Generic;
using System.Linq;



namespace Transport.ly
{
    class Program
    {
        static void Main(string[] args)
        {
            Inventory transportLy = new Inventory("Transport.ly", Loader.LoadScenarioSchedule(), Loader.LoadOrders());

            MainMenu(transportLy);
        }

         static void MainMenu(Inventory inventory) {

            while (true)
            {
                int userChoice;

                do
                {
                    Console.Clear();
                    DisplayMAinMenu();
                    Console.WriteLine(Constants.Messages.QuiApplicationMenu);

                } while (!int.TryParse(Console.ReadLine(), out userChoice) || userChoice < 0 || userChoice > 3);

                Console.Clear();

                switch (userChoice)
                {
                    case 1:
                        MenuLoadSchedules(inventory);
                        break;
                    case 2:
                        DisplayLoadedSchedules(inventory.GetLoadedSchedules());
                        Console.WriteLine();
                        Console.WriteLine(Constants.Messages.PressAnyKey);
                        Console.ReadKey();
                        break;
                    case 3: DisplayFlights(inventory.GenerateFlights(), inventory.GetOrders());
                        Console.WriteLine(Constants.Messages.PressAnyKey);
                        Console.ReadKey();
                        break;
                    case 0:
                        Environment.Exit(0);
                        break;
                    default:
                        Console.WriteLine(Constants.Messages.Tryagain);
                        break;
                }
            }
        }


        static void MenuLoadSchedules(Inventory inventory)
        {
            while (true)
            {
                int option;

                do
                {
                    Console.Clear();

                    DisplayAvailableSchedules(inventory.GetAvailableSchedules());
                    Console.WriteLine(Constants.Messages.ReturnToMainMenu);

                } while (!int.TryParse(Console.ReadLine(), out option) || option < 0 || !inventory.GetAvailableSchedules().ContainsKey(option) && option != 0);

                if (option != 0)
                {
                    inventory.LoadSchedule(option);
                    Console.Clear();
                    Console.WriteLine("Schedule : " + option + " loaded");
                    Console.WriteLine(Constants.Messages.PressAnyKey);
                    Console.ReadKey();

                }
                else {

                    return;
                }

                Console.Clear();   
            }
        }



        static public void DisplayMAinMenu()
        {
            Console.WriteLine(Constants.Header.MainMenu);
            Console.WriteLine();
            foreach (string option in Constants.MenuOptions.MainMenu)
                Console.WriteLine(option);

        }

        static public void DisplayAvailableSchedules(Dictionary<int, Schedule> availableSchedules) {

            Console.WriteLine(Constants.Header.ChooseScheduleToLoad);
            Console.WriteLine();

            foreach (KeyValuePair<int, Schedule> entry in availableSchedules)
            {
                Console.WriteLine(entry.Key+ ". Departure: " + entry.Value.Departure + " Arrival: " + entry.Value.Arrival + " Day: " + entry.Value.Day);
            }
        }

        static public void DisplayLoadedSchedules(Dictionary<int, Schedule> schedules)
        {

            Console.WriteLine(Constants.Header.LoadedSchedules);
            Console.WriteLine();
            foreach (KeyValuePair<int, Schedule> entry in schedules)
            {
                Console.WriteLine(entry.Key + ". Departure: " + entry.Value.Departure + " Arrival: " + entry.Value.Arrival + " Day: " + entry.Value.Day);
            }
        }

        static public void DisplayFlights(List<Flight> flights, List<Order> AllOrder) {

            foreach (Order order in AllOrder)
            {

                Console.WriteLine(Constants.Header.BatchOfOrders);
                Console.WriteLine();


                if (order.Loaded)
                {
                    //get other informations

                    foreach (Flight flight in flights)
                    {
                        if (flight.Orders.FirstOrDefault(item => item.Code == order.Code && item.Destination == order.Destination) != null) {

                            Console.WriteLine("order: "+ order.Code+ ", flightNumber: "+flight.Number + ", departure: "+flight.Schedule.Departure+
                                ", arrival: "+flight.Schedule.Arrival+", day: "+flight.Schedule.Day);

                        }
                    }
                }
                else {

                    Console.WriteLine("order: "+order.Code+", flightNumber: not scheduled");

                }
            }
        }


    }
}
\$\endgroup\$
2
\$\begingroup\$

As it was a coding interview, you should give importance to some points. Here are those what I think from your coding exercise:

  1. You need to complete your exercise within the time specified. So, don’t waste you time to beautifying things or creating more functionalities which are not required. This kind of interview is conducted to see your skills and experience which is clearly mentioned.
  2. Make sure your output matches with sample output. If you an average developer, a single character can harm you. But if your code is extraordinary level then it may not be an issue.
  3. Focus on the coding styles like any principles or design patterns need to use. For this you need use best practices and SOLID principle of OOD. So, you must not violate SOLID principle while coding.
  4. Take few minutes to think how you should design classes, interfaces etc. If you have well amount of experience, then it wouldn’t take much time to design thing in your head.
  5. In scenario, flight schedules are given. So, you need to create Schedule class. These 6 schedules will be created using collection which are hard coded for this exercise so save time. However, you created schedule in a JSON file which is a waste of your time to complete this exercise.
  6. Each plane has a capacity of 20 box each and each box represents 1 order. So, you need to create a Plane/Flight class and Order class. A Plane/Flight class will have a property of Schedule class, a collection of Order property and integer Capacity property. You can hard code or use constant for capacity as it’s set to 20 but it’s good to make it flexible. Furthermore, you need to read Orders from JSON file.

USER STORY #1

  • It gives you full information about Schedule class properties. It will have FlightNumber, Departure, Arrival, Day and IsLoaded properties. It also said that you don’t need to load Orders as you only need to show not loaded schedules.

USER STORY #2

  • It says Order has priority and it should be loaded in Plane/Flight using priorities. So, Order class will have Code, Destination, Priority and Schedule properties. Though orders are in JSON file are arranged by priorities but it’s good to sort by priority.

Here are some code samples:

class Schedule
{
    //use auto properties
    public int FlightNumber { get; set; }
    public string Departure { get; set; }
    public string Arrival { get; set; }
    public int Day { get; set; }
    public bool IsLoaded { get; set; }

    public override string ToString()
    {
        //use string interpolation
        return $"{FlightNumber}. Departure: {Departure},  Arrival: {Arrival}, Day: {Day}";
    }
}

class Flight
{
    //use auto properties
    public int Capacity { get; private set; }
    public Schedule Schedule { get; private set; }
    public IList<Order> Orders { get; set; }

    public Flight(int capacity, Schedule schedule)
    {
        Capacity = capacity;
        schedule.IsLoaded = true;
        Schedule = schedule;
        Orders = new List<Order>();
    }

    public string FlightSchedule()
    {
        //use string interpolation
        return $"Flight: {Schedule.FlightNumber}, departure: {Schedule.Departure}, arrival: {Schedule.Arrival}, day: {Schedule.Day}";
    }
}

class Order
{
    //use auto properties
    public int Priority { get; set; }
    public string Code { get; set; }
    public string Destination { get; set; }
    public Schedule Schedule { get; set; }

    public bool IsNotLoaded()
    {
        return Schedule == null;
    }
}

class Menu
{
    public string Header { get; set; }
    public IList<string> Items { get; set; }
    public int ExitValue { get; set; }

    public Menu()
    {
        Items = new List<string>();
    }
}

class FileReader
{
    public static string ReadAllText(string path)
    {
        return File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), path));
    }
}

interface IOrderRepository
{
    IList<Order> GetOrders();
}

class OrderRepository : IOrderRepository
{
    public IList<Order> GetOrders()
    {
        var jsonString = FileReader.ReadAllText("JSON Files\\coding-assigment-orders.json");

        var orders = JsonConvert.DeserializeObject<Dictionary<string, Order>>(jsonString).Select(p =>
        new Order { Code = p.Key, Destination = p.Value.Destination, Priority = int.Parse(p.Key.Substring(p.Key.LastIndexOf('-') + 1)) }).ToList();

        return orders;
    }
}

interface IScheduleRepository
{
    IList<Schedule> GetSchedules();
}

class ScheduleRepository : IScheduleRepository
{
    public IList<Schedule> GetSchedules()
    {
        //use implicitly typed variables
        var flightNo = 1;
        var day = 1;
        var schedules = new List<Schedule>();

        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YYZ", Day = day, IsLoaded = false });
        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YYC", Day = day, IsLoaded = false });
        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YVR", Day = day, IsLoaded = false });

        day++;
        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YYZ", Day = day, IsLoaded = false });
        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YYC", Day = day, IsLoaded = false });
        schedules.Add(new Schedule { FlightNumber = flightNo++, Departure = "YUL", Arrival = "YVR", Day = day, IsLoaded = false });

        return schedules;
    }
}

class MenuManager
{
    public virtual int DisplayAndRead(Menu menu)
    {
        Console.Clear();
        Console.WriteLine("======= {0} =======\n", menu.Header);

        foreach (var item in menu.Items)
        {
            Console.WriteLine(item);
        }

        Console.Write("\nEnter your choice: ");

        int userInput;
        int.TryParse(Console.ReadLine(), out userInput);

        return userInput;
    }
}

class InformationManager : MenuManager
{
    public override int DisplayAndRead(Menu menu)
    {
        Console.WriteLine(menu.Header);

        foreach (var item in menu.Items)
        {
            Console.WriteLine(item);
        }

        Console.Write("\nPress any key to return to main menu... ");
        Console.ReadKey();

        return 0;
    }
}

class ScheduleManager
{
    public static string LoadedMessage(Schedule schedule)
    {
        return $"Schedule {schedule.FlightNumber} loaded";
    }
}

class ItinenaryManager
{
    public static string Itinerary(Order order)
    {
        return order.IsNotLoaded() ? $"order: {order.Code}, flightNumber: not scheduled"
            : $"order: {order.Code}, flightNumber: {order.Schedule.FlightNumber}, departure: {order.Schedule.Departure}, arrival: {order.Schedule.Arrival}, day: {order.Schedule.Day}";
    }
}

class InventoryManager
{
    public IList<Order> Orders { get; private set; }
    public IList<Flight> FlightsScheduled { get; private set; }
    public IList<Schedule> Schedules { get; private set; }

    public InventoryManager()
    {
        FlightsScheduled = new List<Flight>();
        Schedules = new ScheduleRepository().GetSchedules();
    }

    public void ProcessFlightScheduleMenuUserChoice(int userChoice)
    {
        if (userChoice > 0 && userChoice <= Schedules.Count)
        {
            var selectedSchedule = Schedules.FirstOrDefault(s => !s.IsLoaded && s.FlightNumber == userChoice);
            if (selectedSchedule != null)
            {
                var scheduledFlight = new Flight(20, selectedSchedule);
                FlightsScheduled.Add(scheduledFlight);
                FlightsScheduled = FlightsScheduled.OrderBy(f => f.Schedule.FlightNumber).ToList();
                DisplayScheduleLoadedMessage(selectedSchedule);
            }
        }
    }

    public void DisplayScheduleLoadedMessage(Schedule schedule)
    {
        var menu = new Menu()
        {
            Items = new List<string>()
            {
                $"{ScheduleManager.LoadedMessage(schedule)}"
            }
        };

        new InformationManager().DisplayAndRead(menu);
    }

    public void DisplayLoadedSchedules()
    {
        var menu = new Menu()
        {
            Header = "\n======= Loaded schedules =======\n"
        };

        foreach (var flight in FlightsScheduled)
        {
            menu.Items.Add(flight.FlightSchedule());
        }

        new InformationManager().DisplayAndRead(menu);
    }

    public void DisplayFlightItineraries()
    {
        LoadOrdersInFlights();

        var menu = new Menu()
        {
            Header = "\n======= Flight itineraries =======\n"
        };

        foreach (var order in Orders)
        {
            menu.Items.Add(ItinenaryManager.Itinerary(order));
        }

        new InformationManager().DisplayAndRead(menu);
    }

    private void LoadOrdersInFlights()
    {
        Orders = new OrderRepository().GetOrders().OrderBy(o => o.Priority).ToList();

        foreach (var schedule in Schedules)
        {
            if (schedule.IsLoaded)
            {
                var loadedFlights = FlightsScheduled.Where(f => f.Schedule == schedule).ToList();

                foreach (var flight in loadedFlights)
                {
                    var flightOrders = Orders.Where(o => o.IsNotLoaded() && o.Destination == schedule.Arrival).Take(flight.Capacity).Select(o => { o.Schedule = schedule; return o; }).ToList();
                    flight.Orders = flightOrders;
                }
            }
        }
    }

    public Menu GetFlightScheduleMenu()
    {
        var menu = new Menu
        {
            Header = "Choose a schedule to load"
        };

        foreach (var item in Schedules)
        {
            if (!item.IsLoaded)
            {
                menu.Items.Add(item.ToString());
            }
        }

        menu.ExitValue = Schedules.Count + 1;
        menu.Items.Add($"{menu.ExitValue}. Main menu");

        return menu;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var inventory = new InventoryManager();

        ReadMainMenuUserChoice(inventory);
    }

    private static void ReadMainMenuUserChoice(InventoryManager inventory)
    {
        int userChoice;
        Models.Menu menu = GetMainMenu();

        do
        {
            userChoice = new MenuManager().DisplayAndRead(menu);
            ProcessMainMenuUserChoice(userChoice, inventory);
        } while (userChoice != menu.ExitValue);
    }

    private static void ProcessMainMenuUserChoice(int userChoice, InventoryManager inventory)
    {
        switch (userChoice)
        {
            case 1:
                ReadFlightScheduleMenuUserChoice(inventory);
                break;
            case 2:
                inventory.DisplayLoadedSchedules();
                break;
            case 3:
                inventory.DisplayFlightItineraries();
                break;
            case 4:
                Environment.Exit(0);
                break;
        }
    }


    private static void ReadFlightScheduleMenuUserChoice(InventoryManager inventory)
    {
        int userChoice;
        Models.Menu menu;

        do
        {
            menu = inventory.GetFlightScheduleMenu();
            userChoice = new MenuManager().DisplayAndRead(menu);
            inventory.ProcessFlightScheduleMenuUserChoice(userChoice);
        } while (userChoice != menu.ExitValue);
    }

    private static Models.Menu GetMainMenu()
    {
        var menu = new Models.Menu
        {
            Header = "Transport.ly",
            Items = new List<string>()
            {
                "1. Load a schedule",
                "2. List out loaded flight schedules",
                "3. Generate flight itineraries",
            }
        };

        menu.ExitValue = menu.Items.Count + 1;
        menu.Items.Add($"{menu.ExitValue}. Exit");

        return menu;
    }
}

Please check code below each comment and know how to write it. I should suggest you to use ReSharper for Visual Studio. It will help you to make your code little better and inform about code issues. However, ReSharper can’t implement any principles or design patters.

I hope you've read other comments, so I've skipped those.

\$\endgroup\$
3
\$\begingroup\$

The main thing which can be recognized as a Junior Developer code is a poor possibility of code support in the future. To archive such a point you need to use some common architectural patterns. First of all the code should be tested and error handled. Also, you were asked to provide SOLID code which again means a bunch of patterns (IoC as DI is a must today in the development cycle). For example, the Loader class is not SOLID at all. Try to use microservices architecture for this purpose. Also, I can see a strange code like:

return _schedules.Where(s => s.Value.Loaded == false)
                        .ToDictionary(dict => dict.Key, dict => dict.Value);

I mean why this:

s.Value.Loaded == false

and not just

s=>!s.Value.Loaded

Actually, after this row of code, I would decline your candidature for the Middle developer role.

\$\endgroup\$
  • 1
    \$\begingroup\$ Could you define IoC as DI for those of us that don't understand? \$\endgroup\$ – pacmaninbw Oct 20 at 13:38
  • \$\begingroup\$ IoC - is Inversion Of Control; DI - Dependency Injection which is a private case of IoC pattern. This is a very big theme to highlight it with one comment. \$\endgroup\$ – Alexander Pavlenko Oct 20 at 17:32
  • \$\begingroup\$ Thx for your response. you told me that the loader class is not SOLID. The goal of my loader class was to load the JSON files into the programs. I don't quite understand how I could use microservice architecture to do that. Could you give me more details about the implementation of that architecture? \$\endgroup\$ – coldistric Oct 21 at 13:45
  • \$\begingroup\$ Microservice architecture is an insanely off-topic suggestion for an exercise that is expected to take no more than 90 minutes. As an interviewer I'd dismiss a microservices answer as a massive overengineering and an inability to work to a given schedule. \$\endgroup\$ – Flater Oct 22 at 14:35
  • 2
    \$\begingroup\$ Note that “SOLID” here has a specific meaning. Here’s a quick intro scotch.io/bar-talk/… \$\endgroup\$ – John Hascall Oct 22 at 18:18
2
\$\begingroup\$

I also think you are using older styles. For example:

private bool _loaded;
public bool Loaded { get => _loaded; set => _loaded = value; }

Is awkward and really should have a better name:

public bool IsLoaded {get; set;}

Looks like they would appreciate some OOP. I would think there would be a class for airports. Just Googling on 3 letter airport codes and Wikipedia, I whipped this up in 10 minutes:

public class Airport
{
    private Airport() { }

    public string Id { get; private set; }
    public string Name { get; private set; }
    public string City { get; private set; }
    public TimeZoneInfo TimeZone { get; private set; }
    // add other pertinent properties such as Province or Country

    public override string ToString() => $"{Name} ({Id}), {City} {TimeZone.DisplayName}";

    // Helpful link on IATA 3 letter codes:
    // https://www.nationsonline.org/oneworld/IATA_Codes/IATA_Code_Y.htm

    public static Airport YUL => new Airport
    {
        Id = "YUL",
        Name = "Dorval",
        City = "Montreal",
        TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
    };

    public static Airport YYZ => new Airport
    {
        Id = "YYZ",
        Name = "Toronto Pearson International Airport",
        City = "Toronto",
        TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
    };

    // Calgary and Vancouver left as exercise
}

If they want OOP, give them OOP!

Also, I would not make too many assumptions though they were assumed in the directions. This may be the questioners lulling you into taking short-cuts and making your code too rigid.

  • I would not assume all flights leave only from Montreal's Dorval airport.
  • I would not assume all flights leave exactly at noon.
  • I would not assume the departing and destination airports are in the same time zone or country.

Heeding that advice, if I were to make a Flight class, I would have a Departing airport (not assume it's Montreal), a Destination airport, a DepartingTime (not assuming Noon Montreal), and ArrivingTime. Internally, all DateTime objects would be UTC. Displayed times would be local to the respective airport. That is the departing time is local the the departing airport, but the arrival time would be local the the destination airport, which is why I included TimeZone as a property in the Airport class.

Maybe one acceptable assumption would be that an Unspecified date and time would also be considered local to the respective airport. Or you may prompt for clarity of throw an exception.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.