I can't imagine people remembering numeric offsets for everything.
All assemblers allow using labels for global variables, and in part for this reason, global variables are commonly used in assembly coursework programming where named local variables would have been used in high-level languages.
Also because global variables are allocated and initialized using relatively simple data declarations, whereas using stack storage for local variables requires dynamic allocation, initialization and deallocation, and then of course, offsets relative to the stack pointer rather than absolute addressing via named labels. While we tend to frown on global variables in general programming, many toy/assignment programs have only a main and few or no functions, so global storage is actually reasonable there.
Many local variables and parameters get mapped to registers on most modern machines. It is necessary to identify registers to use for variables, temps, and parameter passing, and using some kind of #define or equate often makes that harder rather than easier. Many programmers prefer to describe variables and their mappings in comments instead of using macros or equates.
Memory is the last resort for mappings of scalar variables, as registers are preferred. These days, we do the smallest necessary amount in assembly (sometimes none at all). And as already noted, we can substitute global variables for local variables when writing toy programs. Among these reasons, using offsets doesn't really hurt as much as you'd think.
There's also reasons that the mappings for a given local variable changes during the progression the function it is in, so have to be adjusted for the situation (e.g. sometimes a parameter moves to another register for reasons of the calling convention; other times from memory to a register for performance; if we don't want the overhead of a frame pointer, then a push will change offsets of things already on the stack). Assembly language is so low level we often don't want to obscure detail.