Spotify
A playlist has a fixed order; what plays next doesn't. Shuffle shouldn't mean physically
reordering the playlist (now two listeners sharing it see different orders) or growing a
NowPlayingQueue.next() method that branches on a boolean - it means the queue asks a
pluggable strategy what's next and never finds out how that answer was decided.
Requirements
Functional
- A user builds a playlist by adding songs pulled from albums and artists.
- Playing a playlist loads its songs into a now-playing queue; the queue exposes the current track and supports skipping forward and backward.
- Shuffle mode changes playback order without altering the playlist's own stored order.
- Every song belongs to exactly one album, and every album to one artist.
Non-functional
- Switching between sequential and shuffled playback must not require the queue to branch internally on a mode flag - the ordering logic is swappable.
- Advancing to the next or previous track must be an O(1) pointer move, not a scan for the current track's position.
Design
NowPlayingQueue holds a fixed track list and a current index; it never decides what "next"
means. That decision belongs to a PlaybackStrategy - SequentialPlaybackStrategy walks the
list in order, ShufflePlaybackStrategy walks a precomputed permutation - so the queue's
next()/previous() are one line each regardless of which strategy is plugged in.
- 1Playing a playlist hands its song list to a fresh queue - the playlist itself is untouched.
- 2The queue starts with a default strategy; the playlist’s stored order is never copied elsewhere as a side effect.
- 3Turning on shuffle swaps the queue’s strategy - it does not touch playlist.songs.
- 4The permutation is computed once here, not recomputed on every skip.
- 5The queue asks the current strategy for the next index and never inspects it further.
- 6Sequential and shuffle strategies answer this identically from the queue’s point of view.
The playlist itself never changes when shuffle is toggled - only the queue's strategy does - which is what keeps a shared playlist's stored order stable no matter who's listening to it on shuffle.
Class diagram
Code
Design decisions
- Playback order is a
PlaybackStrategy, not a boolean on the queue. Ashuffled: boolfield would still need anifsomewhere to act on it; insteadNowPlayingQueue.next()callsstrategy.next(currentIndex)unconditionally; the strategy is the thing that changes, not the queue's code path. - Shuffle precomputes a permutation once, at the moment shuffle is turned on, not on every
next()call.ShufflePlaybackStrategyshuffles an index list up front and walks it like the sequential strategy walks0..n- so toggling shuffle mid-playlist doesn't mean re-deriving randomness every time a listener hits skip. - A
Playliststores songs in one order, period - the queue is a separate object that reads from it. Two listeners playing the same shared playlist on different modes (one shuffled, one sequential) each get their ownNowPlayingQueue; neither can corrupt the playlist's stored order for the other. Song->Album->Artistis a plain composition chain, not a shared registry class. There's no separateCatalogservice here because nothing in this page's scope needs to search across all songs - only to know which album a song belongs to and which artist made it, which a direct reference answers in one hop.- What's missing for a real system: a content-based or collaborative recommendation
engine, cross-device playback handoff, and offline-download state are all real Spotify
features that would sit alongside
PlaybackStrategy(recommendation could even be one more strategy implementation) rather than requiring a change to the queue's shape.