Putting the with in a function is quite nice imo; it increases readability of the pipeline (“Oh, I see: this ‘with’ handles the command …”) … nicely done
I guess the only thing to be aware of is that if any part of the with fails, write_line will try to write out the error-causing value! … which probably won’t work out well as gen_tcp.send/2 expects iodata.