when making a change to one piece of functionality effects a lot of other things, this is generally a bad sign.
usually, it makes sense to try to organize things when possible, that making changes does not have widespread effects.
usual strategies are what I call "modularizing", "layering", and "pipelines".
modularizing is basically breaking parts into independent "black boxes", where code in one "module" ideally minimize dependencies and interactions with code within another module.
layering is basically building an API such that a range of common functionality can essentially be "abstracted out" of the code.
ideally, code building on top of the API needs to not know or care how things work inside the API, nor should the API code care what happens in client code or how it is used.
pipelines are basically where the code is broken up into a number of stages, typically with each stage transforming input into output in some well-defined way. typically either, each stage is stateless, or the existence of state is handled explicitly in the design.
in this case, a piece of code to achieve a task then becomes a number of interconnected stages, with each operating independently of the others.
typically, all this is then applied at various levels. this allows generally getting more things done with less effort, and basically more freedom with going mix-and-match with various parts of the project while minimizing need for large-scale changes.
for game logic, this would generally mean trying to abstract the logic from the entities from the handling of entities themselves.
for example, does the entity-system logic even need to know or care whether the entity is alive or dead? generally not, and instead being alive or dead would be a property of certain types of entities (such as AI controlled mobs). so, the entity system will primarily concern itself with things which are fairly universal.
generally, we also want to isolate any loops or iteration over entities from the logic for the entities themselves. this would mean that general update loops will primarily consist of calling methods in the specific entity objects (this is independent of language choice), which may itself implement the relevant behavior logic.
but, yeah, if things are organized well, than more types of similar work can be done more quickly and with less effort, even if potentially at some cost in terms of additional up-front effort.
though, yes, there is also a problem that too much up-front generalization can also be a problem, resulting in a lot of work for not a whole lot of gain (or a project that is 90% infrastructure and 10% program logic), or use of inappropriate abstractions which don't really fit the use-case, ..., so striking a balance is needed.
some types of tasks are easier to abstract in this way than others.