I find it much easier to reliably accomplish non-standard things with systemd unit definitions, than it used to be with the ill-defined complex set of shell scripts we had before.
systemd management of mounts can be similarly narrow about the types of configurations it supports, and systemd-firewalld just sort of openly only claims it can support simple use-cases.
systemd-journald is also a net loss of flexibility compared to rsyslog but, on the other hand, rsyslog could quickly turn into an inscrutable mess if you used any of the advanced features (rainerscript...), so this may not be an entirely bad thing.
And in general systemd is, well, opinionated. I hate to bang on resolved too much but I just happen to have spent quite a few hours last week figuring out resolved problems. Resolved does not handle "dotless" domains correctly in a lot of existing environments (it's very particular about exactly how the search domain is set up). Poettering has basically responded that it's because dotless domains are stupid and no one should use them, so it won't be changed. I don't necessarily disagree that dotless domains are not a good idea today but it does mean that resolved breaks a lot of older corporate and institutional environments that have been using them successfully for decades. This manifests as "I updated my distro and the intranet stopped working." That kind of breaking change is not very common with core Linux services and isn't going to make many friends in the IT crowd.
But, I am 100% agreement on the whole resolvd thing. It is a complete fiasco for anything but someone's idea of a standard network.
Even the most basic things, like waiting for DNS to be up before mounting a network filesystem has to be done by writing your own units if you don't want to just try and mount and hope for the best.
Consider a situation, where your sh-backed SysV init was missing some function you required. Something between start-stop-daemon() or ifup(). You could throw a bunch of shell commands (note: most shell "programmers" are not capable of doing it properly; they do some '==' comparisons in /bin/sh shebang, don't handle errors, ignore fact that variables might contain "funny" characters etc. - but in general most of the scripts I've seen during my 24 years in Linux was simply badly written, meaning at least using bashizms). And then ...you watch out for every single package update that would overwrite your changes. Or you could polish them and try to push upstream.
Now the situation seems to be worse - you can't just edit some random file to add missing function, you need to write it in source C files and recompile. Not a way for quick and dirty solution.
But instead, you can simply write the same (s)hell commands in a script and call it from appropriate unit. No messing with thousand-lines scripts, no risk of overwrites, no need for upstreaming.
I’m sure there are many other examples.
Honestly, even after 10 years, I still have’t had a single positive interaction with it vs. traditional init. From what I’ve seen, old-school init handled (and continues to handle) the problems systemd “solved” more robustly and elegantly. I don’t get it.