Although definitions can vary, I wouldn't define Unity3D as an Entity System engine. When we talk about Entity System, we should follow the Adam Martin definition.
According his idea, the Systems should be created by the programmer, while in Unity3D the "systems" are predefined in the engine and cannot be extended.
This is an old way to manage Entities and Components, it's more an evolution of the ancient technique where game objects were holding pointers to components compatible with the engine functionalities (like rendering, culling and so on).
Of course when is not possible to extend the "Systems" functionalities, the only way to extend the logic of our entities is to add logic inside Components. This is anyway a step forward from the classic OOP techniques. Component Oriented (I call them Entity Component, without System) frameworks like the one in Unity, push the coder to favor Composition over Inheritance, which is surely a better practice.
All the logic in Unity should be written inside focused MonoBehaviour. Every MonoBehaviour should have just one functionality, or responsibility, and they shouldn't operate outside the GameObject itself. They should be written with modularity in mind, in such a way they can be reused independently on several GameObjects. Monobehaviours also hold Data and their design obviously follows the basic concepts of OOP.
Modern design tends instead to separate data from logic. See for example the MVC or MVP patterns. Data, Views and Logic should be separated to achieve a better code modularity.
The real problem with the Unity Entity Component design is about the complexity needed to put two entities in communication in a reasonable way that doesn't lead to the use of various anti-patterns.
Unity inverts the control of the creation of entities, thus the coder doesn't have any control on the creation of them. Inverting the creation control is a good thing, but Unity doesn't do it in a proper way. Not being able to inject dependencies in Entities is a limitation that forces coders to use anti-patterns in order to overcome all the intrinsics consequences.
Eventually the cleanest option available is to use Singletons in order to share information between entities.
That's why is quite hard to manage and maintain big projects with Unity. I wrote a lot about these problematics in my blog. So if you want you can continue reading my thoughts there:
http://www.sebaslab.com/ioc-container-for-unity3d-part-1/
http://www.sebaslab.com/ioc-container-for-unity3d-part-2/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-ii-inversion-of-control/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iii-entity-component-systems/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iv-dependency-inversion-principle/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-v-drifting-away-from-ioc-containers/
In these posts I extensively discuss about the Unity3D design flaws that hinder the development of big projects and both IoC container and Entity Component System framework as possible solutions.