Code is data like any other data in the ROM. You have to change some of the bytes in the ROM (that the CPU can see at the desired point in the game), in order to add the (code) byte sequence you want.
Either you change bytes that are unused, or bytes that already contain code or data (hence breaking that part) - or you make a guess and try writing your code somewhere anyway (and perhaps see if something breaks). I usually prefer not making guesses, but it can make things difficult.
Then you typically write a jump in an existing piece of code that gets executed, that jumps to your new code sequence (and back). It may have to be executed at a specific point during the game execution, and that defines which piece of code you insert your jump to. If you have free space, you can insert your code roughly at any point in the existing execution flow because you can always move a few instructions of the original code to the new place, in order to get room for the jump itself.
You can use a hex editor and write the code (as hex values = machine code) yourself or you can use an assembler that translates your asm mnemonics into machine code. The assembler may just output a blob of hex that you insert yourself, or it can do that for you as well if you tell it where to output the values (depending on assembler).
You don't typically add anything to the hack (as a patch file) itself, but you modify the patched ROM just like you would modify any unpatched ROM. You can always make a new patch from any differences anyway.