Home John's Interview - Loader Design
Post
Cancel

John's Interview - Loader Design

🌑 Outline

John went for an iOS Interview at TechForGood Organization, which has a system design round. Let’s go through the transcript of the discussion.
Interviewer: Steve
Candidate: John

Steve: Design a loader for a mobile application. It can be accessed anywhere within the application.

Let’s check whether John clarifies all the requirements or jumps to the solution

🌥️ Clear Out Requirement

So John already knew the rules for the interview and started to ask questions.

Let’s read what John clarified:

John: Do we need to design a general-purpose library or part of an application source code?
Steve: A Library.

John: How does the Loader look like? Do we need to support multiple types of Loading UI
Steve: For now only circular arc Loader but the solution should be extendable to support multiple Loader UI.

John: should the Loader have any opaque background?
Steve: Yes, it should support both with or without background.

John: Should the loader support a timer?
Steve: What do you mean by timer?

John: A timer to auto-stop the Loader after some time?
Steve: No, not required for now.

John sums up the requirement in short:

A Loader library must be designed to support multiple loading activity types. For now, circular activity support is required. The loader should be flexible to support a background.

🌓 Solution

This is John’s time ⏳ to think about the design.

After thinking for 10 minutes, the following is a high-level design by John:

High-Level Design

Components:

1. LoaderView
The library’s main UI component handles the request to show and hide the loader. It is also responsible for adding background if required.

2. Activity
Heart of the library and responsible for the layout of the loader with animation.

3. Shape
An interface to represent various shapes for the loader. For example, an Arc Shape is required to implement a circular arc loader.

3. Animation
An interface to represent animation on the activity. For the given problem, a rotation animation struct will implement this.

Steve wants to go further. so he asks for a public interface for the library.

Public Interface

1
2
3
public enum loaderActivityType: Int {
    case circleArcLoader
}
1
2
3
public init(type: loaderActivityType = .circleArcLoader)
func showLoader(inView: View)
func hideLoader()

Steve: Do I need to initialise the loader on every screen?
John: Yes, I designed it in a way that wherever the loader needs to be displayed a new instance should be created, An alternative approach can be a singleton class to construct a loader. However, I Intentionally keep this design so that developers using the library have the flexibility to add a singleton adapter or create multiple instances as per requirement.

Steve: The showLoader method requires a view as an input parameter. can you think of any approach to using the view as an optional func showLoader(inView: View? = nil) ?
John: A parent view is required to display the loader. We can use the application’s main window(iOS) to display the loader if the view is optional and not present. I like the approach of passing a view from the invoking method because accessing the main window from the library might have an unexpected behaviour in case the application has multiple windows.

Steve: is the hideLoader method have a mechanism to check if the loader is visible and then only hide?
John: No, I have not thought of this case, however, I can use some flag to keep the state of the loader.

Detail Design

Steve gets an overview of the approach next, he wants to discuss in detail all the components of the library. He started with the Animation component:

Animation In-Depth

Steve: Would you explain how the Animation component works?
John: This component provides add animation to the activity. For example, a circular loader has a circle that rotates infinitely. The animation component will provide infinite rotation animation.

Steve: How Activity component interact with Animation?
John: The Animation component will have a standard interface for all the possible animations for the Loader. In future when any animation needs to be added they adhere to the standard interface.

John: Can I use paper to explain the idea?
Steve: Sure

John:

1
2
3
protocol LoaderAnimation {
    func addAnimationOnView(_ view: View)
}
1
2
3
4
5
struct InfiniteRotationAnimation: LoaderAnimation {
	func addAnimationOnView(_ view: View) {
      //Rotate Animation implementation
    }
}

The activity component can create an instance of “InfiniteRotationAnimation” and apply it on the view wherever required.

Steve: Great. Let’s move to the Shape component.

Shape In-Depth

Steve: What the Shape component do?
John: This component provides the shapes required for the loader. The shape can be a dot, circle, or anything required for the loader.

Steve: How is it used in the library?
John: The shape component will have a standard interface named Shape. Activity can ask for any shape

1
2
3
protocol Shape: View {
    func setupShape()
}
1
2
3
4
5
struct CircleShape: Shape {
    func setupShape() {
        
    }
}

Steve: What if multiple shapes are required in a loader?
John: The activity role comes here, It is responsible for the init and layout of all shapes required for the loader.

Steve: ok, let’s discuss the Activity then.

Activity In-Depth

Steve: What does this activity component do?
John: This component is the heart of the library. It assembles the shapes required for the Loader with animation.

Steve: What do you mean by Assembles here?
John: Suppose a developer wants a Loader with a circle arc rotating in the centre clockwise. A Circle Arc activity component asks for a circle shape from the shape component and adds clockwise animation on the circle shape.

Steve: So an activity represents a loader type?
John: Yes, to support a Loader type respective activity type needs to be created. Like a Circle Arc Activity for a circular loader, pulse Activity for a circle pulse loader, etc.

Circle Arc Activity
Pulse Activity

Steve: Can you scribble the interface for Activity?
John:

1
2
3
4
5
6
7
protocol ActivityIndicator where Self: UIView {
    var isAnimating: Bool { get set }
    var hideWhenStop: Bool { get set }
    
    func startAnimating()
    func stopAnimating()
}
1
2
3
class CircleArcActivityIndicatorView: View, ActivityIndicator  {
   //Implementation of Circular Arc rotating animation
}
1
2
3
class CirclePulseActivityIndicatorView: View, ActivityIndicator  {
   //Implementation of Circular Pulse animation
}

Loader In-Depth

Steve: What is this Loader component?
John: This provides the public interface which we discussed earlier.

Steve: ok, John I am done and Thanks for coming here for discussion.

John has a secret here that he already worked on the Loader library and it is here 😉

This post is licensed under CC BY 4.0 by the author.

SwiftUI - Fixed vs Dynamic Size Spacer

SwiftUI - Observed vs State Object

Comments powered by Disqus.