Event-driven programming concentrates on the events (messages) and their flow between different software components. If you think about it longer, you'll notice that the notion of events can be found in many types of software. Historically, event-based programming is the most common paradigm for software that deals with direct human interaction. It means that it is a natural paradigm for graphical user interfaces. Everywhere the program needs to wait for some human input, that input can be modeled as events or messages. In such framing, an event-driven program is just a collection of event or message handlers that react to human interaction.
Events also don't have to be a direct result of user interaction. The architecture of any web application is also event-driven. Web browsers send requests to web servers on behalf of the user, and these requests are often processed as separate interaction events. Such requests are, of course, often the result of direct user input (for example, submitting a form or clicking on a link), but don't always have to be. Many modern applications can asynchronously synchronize information with a web server without any interaction from the user, and that communication happens silently without the user's notice.
In summary, event-driven programming is a general way of coupling software components of various sizes, and happens on various levels of software architecture. Depending on the scale and type of software architecture we're dealing with, it can take various forms:
- It can be a concurrency model directly supported by a semantic feature of given programming language (for example, async/await in Python)
- It can be a way of structuring application code with event dispatchers/handlers, signals, and so on
- It can be a general inter-process or inter-service communication architecture that allows for the coupling of independent software components in a larger system
Let's discuss how event-driven programming is different for asynchronous systems in the next section.