AT&T Assembly - Basic loop & write
Let's start with the easy one:

. - hello - You need to understand that hello refers to an address. And that . refers to the "current" address. So . - hello is the distance between the current location and hello; effectively the length of hello.

Just one of those tricks you learn.  While you could manually put the length into len, there's always the chance that someday someone would change the contents of hello, and forget to change len.  Done this way, it's self-maintaining. Being able to compute this at 'assembly time' rather than counting bytes during run time is also a bonus.

As for the code itself, let me start with the main point: Comments.

Assembly can be tricky to code correctly, and sometimes is even harder to maintain.  Especially when you can't figure out what #@%! the guy who was writing it was trying to do.

I realize that this is just a beginner's project.  But you should acquire the habit of commenting early:


Comments at the top of the code telling the purpose of the file.
Comments at the top of routines (and macros) telling what they do.
Comments at the end of individual statements describing the intent.


As an example:

    exit $0 ; Exit the application with return code 0

While to a veteran assembly programmer this comment may seem obvious, to a beginner (and everyone is a beginner at some point), it makes the intent significantly clearer.  Just a few words of text can take a screen full of numbers and symbols and provide clarity.  Maintainers of your code (as well as your future self) will thank you.

Next (in no particular order) I would look at this section of code:


mov $1, %esi
l:
  write $hello, $len
  inc %esi
  cmp $10, %esi
  jle l



As I'm sure you are aware, the purpose of the cmp instruction is to set the flags so that you can use conditional instructions like jle.  However, there are other instructions that adjust those same flags.  For example, dec:

mov $10, %esi
l:
  write $hello, $len
  dec %esi
  jnz l


Nothing magical, but it does save an instruction.

Next we've got 


  Wouldn't it be better to use the %rax registers and syscall instead of int $0x80?


It absolutely would be better to use syscall.  IF you were programming for 64bit.  int 0x80 is correct for 32bit.  And when I say 32/64bit, I'm referring to whether the application is 32 bit or 64bit, not the OS you are running on.

Note: The function number (and where each of the arguments go) are different between int 0x80 and syscall.