Dependancy and target based startup is not a bad idea and can be useful in many scenarios. Its probably not necessary to start many services, though many admins can benefit from the feature where needed and it can actually make administration easier. Since SystemD provides Sys V init, and backwards compatability, the criticism of systemd is a bit overblown as people can simply use system v init features on systemd if they want. The integration of cron, syslog and init was important for being able to launch a service dependant based on say another cron event occuring. There are better ways to do this however using a decentralized model using well defined IPC bus interfaces and protocols allowing for the functionalities to be in seperate processes but allowing processes to communicate with each other, and each a user swappable components as I will describe later. There is no need to have one big monolithic process or poorly understood components which are not swappable and do not communicate using well understood and documented protocols that can facilitate users swapping out components.
I doubt that systemd would be as big of a controversy as it is if the additional functionality was added but not heavily used all over the place for most of the services on the system and the distribution had not felt the need to convert every single service to the new type of init file. Its sort of like people who think they have to use every single C++ feature when C++ is not intended for that, its a bag of tools where the programmer is supposed to choose the tool they need, rather than something where the programmer is supposed to use every single last tool. Instead, the distributions who adopted it felt the need to convert most services over to the new init file format. This created a very much so in your face kind of obtrusiveness that was easily noticeable by many. It was unnecessary in many cases as dependancy based startups can stil even be triggered from System V style initializations. Since systemd supports SysV startup, the majority of init files could have been left in SysV format which would have avoided much controversy. Another possibility is to offer init files in both the old and new formats so people can choose which one they desire.
I believe in a mechanism not policy approach. Systemd's own model of dependancy init are useful in some cases however, are probably overkill for other services. The features should be there for those cases that people may need to use them. Systemd does allow users to the flexibility to use sysV init so the fact is for starting your services you can always have the started from sysV scripts even on Systemd. Ive done it and works fine.
Many complain about the all or nothing approach of systemd. An init system like this should be built around IPC bus, using well defined protocols, interfaces and message formats which are extremely well documented to the public. This way we can get the dependancy based start up, while giving admins complete control and allowing the init system to be built from swappable components. Lets say we wanted to have a daemon started after 5 conditions are fulfilled, 3 other daemons started, the network interface up and 5 minutes elapsed from system boot. The init components that start the 3 prereq daemons would produce IPC bus messages as each of those are started. The kernel would generate a bus message when the network interface would go up. You could write your own init daemon that would watch the bus for all of these events and would also set a 5 minute timer as well, it would keep track of all of these events and when all of them are fulfilled it could then start the daemon and would announce on the bus that it it doing so.
This would allow you to write drop in replacements yourself for any part of the init system. The bus interfaces would all be well documented so you could write your own python script if you wanted to watch the bus for events and be able to start a daemon or process when you see the prerequisite events on the bus. This would allow you to do as much custom logic as yuou need, as you can directly watch the events and messages and write whatever logic you need to of whatever complexity you need to react to the event and messages.
In this bus based design, sysV compatability layers would simply be a client on the bus and would each sysV service is started.
If someone decides to use another init system altogether, the sysV init scripts will still work okay but you would lose the additional functionality that you cannot get from system V scripts alone anyway.
Another gripe that has been heard a lot is the monolithic cron, init and syslog. Under the bus based design, these are completely seperate components that would communicate over the well defined bus interface, so each one of these programs can be easily replaced with whatever the user wants to use. This is a loosely coupled design. Even under systemd, it should be entirely possible for someone to run their own cron daemon if they want to. Under the bus based design, the cron would not have to be bus aware but, its an added benefit should you want to start another service on a cron generated event. As far as the syslog daemon, in the bus design the system consists of two parts, the syslogd reciever daemon that would take syslog messages via syslog protocol from applications, and put the messages on the bus, and any number of other syslog logging daemons that would watch for these messages and would write them to a log file or do something else with them. All of this is user swappable. since applications interact with this daemon, one solution for people who want their own syslog might be to set an environment variable to tell your own servers what syslog daemon to use, which would avoid making any systemd dependants unhappy. In the bus based design, the syslog could easily be swapped out as desired.
It is always important to provide backward compatability, and everything here would support all existing interfaces, standards and conventions including cron, sysV init, syslog protocols and files, etc. The bus design provides all of these components in a completely replaceable and user swappable fashion. With the situation with pulseaudio, for instance, applications should have used a library that supported a fall back to open sound and ALSA type APIs if PulseAudio was not available, in addition to allowing open sound API apps to easily work on PulseAudio systems, and it would be important to provide libraries right off the bat that do this, to assure that things work seemlessly.