I used to have a bunch of over-complicated aliases, but due to their limitations, I now use a mix of aliases and functions, with a few scripts in ~/bin. It’s all a matter of using the right tool. I use aliases for simple things, like default options on some commands. Things that need to happen in the current shell, but are too complex for an alias, are functions. That leaves extra-complex things that I don’t want to write a shell function for as programs in ~/bin, which can be shell, or python, or whatever.