The SECOND thing you should study in C/Arduino development

Literally !

You've heard it a hundred times !
The second thing you should study in Arduino software development...
After setup() and loop() blinking a LED using delay().

Do your homework on using millis() for timing and delays !

Once you master this relatiely simple programming concept, your projects will buzz along - and you'll wonder how you got by without it...

delay() is 'ok' in some rare cases, and often seen in setup() where steps need to be completed in sequence - but once your program is off and running - if it's meant to do somethnig meaningful, and be responsive - delay and closed loops become an obstacle to good programming and an interactive experience.

The concept you need to understand is 'blocking' vs 'non-blocking' program execution.
I could write another treatise - but here's a decent explanation...

Ref written by [nadroj] with edits.

Blocking and non-blocking are just logical names to describe the behaviour of program blocks.
As the name implies, a blocking function blocks the calling function. This means the caller does not do anything until the blocking function returns control.
You can consider this synchronous behaviour, because the interactions are "synchronized" in that the calling function must wait until the called blocking function is finished before continuing.

Conversely, non-blocking functions, of course, do the opposite: they do not require the caller to wait until they're finished.
They simply perform the function, then immediately continue to the next part of the program.
This could be considered "asynchronous" of program elements.

Think of an in-person conversation with someone as asynchronous.
Each person doesn't necessarily wait until the other is finished their sentence.
In a formal conversation with your boss, you're more likely to communicate synchronously: you don't want to interrupt while your boss is talking!
You wait for him/her to finish talking (blocking), then you talk.

I often think that Blink WithOut Delay thinking should be the first thing, since it seems that once folk Blink WITH Delay they can't get that thinking out of their heads. So Blink WITHOUT Delay first, then explain that sometimes there's a place for delay().

i remember learning it as novice back in the days, then i reached a part with 2 ways of blinking an LED, one with delay() which was of course the plain/simple one and the other got me like W T F, 8 lines of codes (millis()) vs 3 lines of codes(delay()) just to accomplish same task ?

but now i am truly experiencing the wonders of millis() as non blocking way of 'virtually' waiting.
tell you what, delay() itself is made of millis() in it's definition