
A feed ranking component often depends on feature providers, scorers, clocks, loggers, and fallback policies. Interviewers use this question to evaluate whether you can design code that is modular, testable, and resilient.
Design an interface for ranking feed items and explain how you would structure dependency injection, test seams, and error handling.
Your answer should address:
Focus on code-level design rather than large-scale distributed architecture. The interviewer expects clear interfaces, sensible abstractions, examples of injectable dependencies, and practical handling of recoverable vs non-recoverable errors. You should discuss trade-offs, not just list patterns.
Dependency injection means the ranker receives collaborators such as scorers, feature fetchers, and loggers through its constructor or method parameters instead of creating them internally. This reduces coupling, makes behavior configurable, and allows tests to substitute controlled implementations.
class FeedRanker:
def __init__(self, scorer, feature_provider, fallback_policy, logger):
self.scorer = scorer
self.feature_provider = feature_provider
self.fallback_policy = fallback_policy
self.logger = logger
A test seam is any place where production behavior can be replaced or observed in tests. Interfaces, adapters, clocks, random number generators, and retry policies are common seams because they let you simulate success, latency, malformed data, and exceptions deterministically.
class FakeScorer:
def score(self, item, features):
return features.get('base_score', 0)
Not all errors should be handled the same way. A good design separates validation errors, dependency failures, timeouts, and internal logic bugs so the ranker can decide whether to retry, skip an item, fall back to a simpler ranking, or fail fast.
class FeatureTimeout(Exception):
pass
class InvalidItemError(Exception):
pass
Ranking systems should often degrade gracefully instead of crashing the entire request. If personalized scoring fails, the ranker may use a default score, recency sort, or a cached result while still emitting logs and metrics for observability.
if feature_error:
return fallback_policy.rank(items)
Interfaces should define clear input and output contracts, including ordering guarantees, handling of missing features, and exception behavior. This makes dependencies swappable and prevents hidden assumptions from leaking across components.
class Scorer:
def score(self, item, features):
raise NotImplementedError