This is what is use in my day to day life too:
I feel machine coding round is a very interesting where we can gauge candidate's analytical skills + design skill. I have given multiple machine coding rounds and have practiced them and have somewhat understood the pattern of how to approach the problem. Vishal has given a list of youtube channels I think those will help you to understand and tackle the problems. The videos are really good and they give a good overall sense of what to expect in a machine coding round. But what i believe is that most of them have created the tutorial for youtube audience and they have taken a lot of time in solving one question and then presenting it to you. So even if you watch the videos it sometimes doesn't help.
What you actually need is an approach.
I am assuming you have basic knowledge of classes, interfaces, abstract classes, [not required but good if you know this: very basic knowledge of some simple design patterns (like Singleton, Builder)}
I would like to list down some points and lets tackle it one by one:
1: Models and relations
Whenever you get a problem, Let's say designing a Conference room etc etc. You can think of some basic models (classes) like: Building, Floor, Room etc.
Try to think of as many models you can and then reject some of those considering the system. For Example: for elevator system design many people include User class models and design it too, which is clearly not required in the "Elevator System". We can try to assume it is already there.
Identify the relations between these models. There can be a list of Buildings, building can have multiple floors, floors can have multiple conf. rooms.
Tip: Do not go into multiple types of buildings, rooms, etc etc creating a unnecessary inheritance hierarchy(it will confuse us)
Summary:
Use simple models and relations at first. Once you have figured out basic models discuss with the interviewer "I have some models and class overview to start wtih ...."
Once discussed about the type of models and if they are okay with it go ahead to the next step. else refactor the models a bit (maybe you added a roomColor property to room which is not required as per interviewer then refactor it)
2: Be SOLID
Now comes the interesting part, crux of the interview.
S: Single responsibility principle
Identify only single responsibility to a model or a model service which acts on models. Single responsibility doesn't mean that only writing one function but it should only focus on one area that can comprise of multiple functions. Ex: It should interact with DB. so the functions can be read(), write() etc etc. (multiple functions for one single concern i.e talk with DB)
Lets say we are building a Leave management system for an employee. So we can have a function in employee class
applyForLeave(start, end):
cal = getCal()
for(start to end):
day = cal.getDay()
day.setOff()
log(I am out now)Here the employee class is doing to much. It is getting the company calendar and marking days off by its own. Which should be ideally handled by Calendar class.
If tomorrow something changes in the logic of marking a leave we will also need to change the logic in Employee class, but hey it isnt a responsiblity of an employee, But HEY you only provided that responsibility to the employee.
Refactor it:
applyForLeave(start, end):
cal = getCal() // cal can be an object in employee as each employee can have his/her own cal.
cal.markForLeave(start, end, emplId) // this takes care of it
log(I am out now)2: O and D: Open for extension but closed for Modification, Dependency Injection
These two sometimes go hand by hand but are totally different. Just merging both of them here with a common example.
Lets say we are building a news platform, whenever a article is published we send it first to our CEO and CTO..
class Publisher:
publishArticle(article a):
sendTo("CEO", a)
sendTo("CTO",a)
Yes this is good now. But wait now we want to send it to CTO too. Now what? Simple just add a line sendTo("CTO",a). But see, we have changed this file and added a line and we will have to test this line works (we know but we have to perform some unit testing/integration testing to be assured so that this doesn't break). So we try to code in such a way that we shouldn't change our existing code. Sometimes the interviewer will expect different scenarios like this and will give you at the end of interview and ask u abt the changes to be made for sending it to CEO.
Solution: Dont try to hardcode. Idenitfy this hardcoded piece can require frequent change. Therefore instead of changing it, pass it as a dependency i.e you are controlling the behavior of this class by passing a list of required people.
constructor(list<People> cxo)
this.cxo=cxo
publishArticle(a):
for cxo in this.cxo:
sendTo(cxo, a)As we are passing the dependency here to the Publisher class (in the constructor) then we are injecting a dependency and not hardcoding it in the class. So there we can also achieve a dependency injection. So where a class is having a dependency on other class/interface try to inject it in constructor and then use it. This will help you in testing the code as you can now pass any values in the list.
I and L: Interface Segregation, Liskov substitution pricniple
These two are not commonly used and not checked by interviewers mostly as these require some kind of subtyping and some relations among classes. So try to avoid these. Also Liskov is related to inheritance and we should minimise our use of inheritance (sometimes we need it but liskov can be understood from some of the Youtube channels mentioned by Vishal)
3: Coding
Start coding:
We are often confused where to start the coding from.
First code the classes basic structure.
Then follow the following flow and design as if you are designing and API which is going to be hit by someone else (the Main class)
Controller (api hook) ------> calls the service ---------> Service Class -------> handles some business logic on models and rquest ----> Data layer (storing data, real DB or inmemory hashmap for coding locally)
This will give you clarity and you will be able to solve it quickly.
At the end do mention what can go right and what can go wrong. Give examples like : Ex- We haven't handled for a different subtype, maybe we haven't properly defined the responsibility of class and it may change in future(this happens and is okay, responsibilities change and then in that case you have to touch the class), We can add design patterns to scale to newer models easily (if you know about the tradeoffs between design patterns, lets say strategy pattern can be used if there are lot sub-classes which differ only in implementation strategy so prefer Strategy Design Patterns instead of inheritance etc etc)
If you have any specific doubt in any stage feel free to comment