Online Auction
An auction is a broadcast problem wearing an e-commerce costume. The moment someone outbids
the current leader, every other bidder watching that item needs to find out - and the
Auction class shouldn't need to know who's watching or how many of them there are.
Requirements
Functional
- An
Auctionis created for anItemwith a starting price and a closing time. - A
Bidderplaces aBid; it's only accepted if it's higher than the current highest bid and the auction hasn't closed. - Every bidder who has previously bid on the item gets notified when a new highest bid comes in, without polling.
- When the closing time passes, the auction closes and the highest bidder wins; no further bids are accepted.
Non-functional
Auctionmust not hold references to specific bidder types or notification channels (email, push, in-app) - adding a new notification method should not changeAuction.- Rejecting a low bid or a bid on a closed auction should be immediate and never mutate auction state.
Design
Auction is the Subject in an Observer relationship: every Bidder who places a bid
becomes a subscriber, and Auction.placeBid calls notifyOutbid on all of them the instant
a new high bid lands - it has no idea whether a Bidder is a person, a bot, or a proxy
bidding service, only that it implements AuctionObserver.
- 1Alice's bid becomes the new highest; she is added as an observer.
- 2Bob outbids Alice; he too is registered as an observer of this auction.
- 3The auction never calls Alice's email provider directly - it just calls the observer interface.
- 4Alice reclaims the lead after being notified.
- 5Bob is notified in turn - the notification list grows with every new bidder, unknown to Auction itself.
Closing the auction is a one-way transition - Auction.close() sets a flag that
placeBid checks first, so a bid racing the closing time either lands cleanly before close
or is rejected cleanly after it, never half-applied.
Class diagram
Code
Design decisions
- Notification is Observer, not
Auctioncalling aNotificationServicedirectly. A direct call would forceAuctionto know about email templates, push tokens, or whatever channel bidders prefer. Observer flips that -Auctiononly knows it has a list of things that want to hear about outbids, and eachBidderdecides for itself what "getting notified" means. - A
Biddersubscribes by bidding, not through a separatewatch()call. Coupling subscription to the act of bidding matches how real auctions work - you don't get outbid alerts for an item you've never bid on - and it means there's no separate watch-list state that could drift out of sync with who's actually bidding. isClosedis checked at the top ofplaceBid, before the price comparison. Checking price first and closed-status second would let a technically-valid high bid slip through a few milliseconds after closing time under the wrong ordering; closed-status first means a closed auction rejects every bid uniformly, no matter how good it is.- What's missing for a real system: notifications here fire synchronously inside
placeBid, which means a slow observer (a flaky push provider) blocks the bid itself - a production system would queue notifications and letplaceBidreturn immediately, and closing on a timer needs a scheduler to callclose()rather than relying on every caller to check the clock themselves.