The first place to start is the emulator. I installed spectemu (xspect) since it was available through debian's apt-get. It worked from the start; I didn't have to hunt down roms like other emulated platorms (68k, C64). If you're following along, at this point you should go download some existing Spectrum games and test everything out, make sure it works.
Next I installed z80asm and downloaded a simple assembly language program. Assembled it, loaded it into xspect and watched nothing happen. The output of z80asm is binary z80 machine code. The output of z80asm needs a piece of code added to the beginning of your binary file to get the Spectrum to load it. It also needs to be in a .tap file format. This code can be machine code, or basic. You don't have to understand, you just have to know it's required.
What to do? I was directed towards BIN2TAP and BIN2CODE on the SevenuP website. They have an .exe version for windows/dos, but also the c source code, which compiled fine with gcc. I have the files including compiled executables for linux x86 on my website here.
Many of the simple asm files I found for spectrum wouldn't assemble, or when if they did didn't work when run. I then thought to check the 99 bottles of beer website, and downloaded the Spectrum Z80 assembly version. It assembled without errors, and ran flawlessly. The 99 Bottles website is a great place to find a simple (but not too simple) program in almost any computer language you can think of, and it's often helpful when one needs a reminder after a few years away from a language.
Here's a link to the .tap and the .asm files of my Hello World app. Let it underwhelm you...
; Hello World in Z80 assembly language.
; Assembles for ZX Spectrum
; Assembled/Tested under linux with the following tools...
; z80asm $@.asm ; utils/bin2tap a.bin $@.tap ; xspect $@.tap
; Author: Nathanial Hendler ; retards.org
; Adapted from Damien Guard's 99 Bottles of Beer on the wall...
; Adapted from the Alan deLespinasse's Intel 8086 version
ld a, 2 ; channel 2 = "S" for screen
call $1601 ; Select print channel using ROM
ld hl,line ; Print line
printline: ; Routine to print out a line
ld a,(hl) ; Get character to print
cp '$' ; See if it '$' terminator
jp z,printend ; We're done if it is
rst 16 ; Spectrum: Print the character in 'A'
inc hl ; Move onto the next character
jp printline ; Loop round
line: defb 'Hello, world.',13,'$'
Here's the bash script I use to assemble, convert to tape, and run the program; in case anyone cares (no error checking because I never make mistakes)...
# Usage: ./makez80 hello
z80asm $@.asm ; utils/bin2tap a.bin $@.tap ; xspect $@.tap
Lastly, I found zxbasic on http://www.boriel.com/. It's a set of python scripts, and it includes one that assembles and outputs .tap files. It seems like an interesting suite of tools, and the fact that they're written in python makes them appealing for their hackability.