From 8444d7d1d53c5a0120013d32e42a25ebfc75c240 Mon Sep 17 00:00:00 2001 From: Roman Mogilatov Date: Wed, 30 Mar 2016 17:10:43 +0300 Subject: [PATCH] Add di_in_python page to the introduction --- docs/main/introduction/di_in_python.rst | 96 ++++++++++++++++++++++--- docs/main/introduction/index.rst | 8 ++- docs/main/introduction/key_features.rst | 2 + docs/main/introduction/structure.rst | 2 + docs/main/introduction/what_is_di.rst | 18 ++--- examples/di_demo/ioc_example.py | 2 +- examples/ioc_demo/car_engine_1.py | 18 +++++ examples/ioc_demo/car_engine_2.py | 18 +++++ 8 files changed, 142 insertions(+), 22 deletions(-) create mode 100644 docs/main/introduction/key_features.rst create mode 100644 docs/main/introduction/structure.rst create mode 100644 examples/ioc_demo/car_engine_1.py create mode 100644 examples/ioc_demo/car_engine_2.py diff --git a/docs/main/introduction/di_in_python.rst b/docs/main/introduction/di_in_python.rst index 7e111676..0efb1be7 100644 --- a/docs/main/introduction/di_in_python.rst +++ b/docs/main/introduction/di_in_python.rst @@ -1,10 +1,88 @@ -Dependency Injection in Python ------------------------------- +Dependency injection and inversion of control in Python +------------------------------------------------------- -Interesting but, dependency injection is not very popular topic in Python. -The things are so because Python is an awesome language. Your eyes are opened -and your hands are free while you are using Python. In practice this means that -you can do dependency injection in Python in quite an easy way because language -itself helps you to do this. At the same time, even the thins are so, you still -have to do some work. Another one 'minor' problem is that there are several -ways to do dependency injection container. +Originally, dependency injection pattern got popular in languages with static +typing, like Java. Dependency injection framework can +significantly improve flexibility of the language with static typing. Also, +implementation of dependency injection framework for language with static +typing is not something that one can do shortly, it could be quite complex +thing to be done well. + +While Python is very flexible interpreted language with dynamic typing, there +is a meaning that dependency injection doesn't work for it as well, as it does +for Java. Also there is a meaning that dependency injection framework is +something that Python developer would not ever need, cause dependency injection +could be implemented easily using language fundamentals. + +It is true. + +Partly. + +Dependency injection, as a software design pattern, has number of +advantages that are common for each language (including Python): + ++ Dependency Injection decreases coupling between a class and its dependency. ++ Because dependency injection doesn't require any change in code behavior it + can be applied to legacy code as a refactoring. The result is clients that + are more independent and that are easier to unit test in isolation using + stubs or mock objects that simulate other objects not under test. This ease + of testing is often the first benefit noticed when using dependency + injection. ++ Dependency injection can be used to externalize a system's configuration + details into configuration files allowing the system to be reconfigured + without recompilation (rebuilding). Separate configurations can be written + for different situations that require different implementations of + components. This includes, but is not limited to, testing. ++ Reduction of boilerplate code in the application objects since all work to + initialize or set up dependencies is handled by a provider component. ++ Dependency injection allows a client to remove all knowledge of a concrete + implementation that it needs to use. This helps isolate the client from the + impact of design changes and defects. It promotes reusability, testability + and maintainability. ++ Dependency injection allows a client the flexibility of being configurable. + Only the client's behavior is fixed. The client may act on anything that + supports the intrinsic interface the client expects. + +.. note:: + + While improved testability is one the first benefits of using dependency + injection, it could be easily overwhelmed by monkey-patching technique, + that works absolutely great in Python (you can monkey-patch anything, + anytime). At the same time, monkey-patching has nothing similar with + other advantages defined above. Also monkey-patching technique is + something that could be considered like too dirty to be used in production. + +The complexity of dependency injection pattern implementation in Python is +definitely quite lower than in other languages (even with dynamic typing). + +.. note:: + + Low complexity of dependency injection pattern implementation in Python + still means that some code should be written, reviewed, tested and + supported. + +Talking about inversion of control, it is a software design principle that +also works for each programming language, not dependending on its typing type. + +Inversion of control is used to increase modularity of the program and make +it extensible. + +Main design purposes of using inversion of control are: + ++ To decouple the execution of a task from implementation. ++ To focus a module on the task it is designed for. ++ To free modules from assumptions about how other systems do what they do and + instead rely on contracts. ++ To prevent side effects when replacing a module. + +Let's go through next example: + +.. literalinclude:: ../../../examples/ioc_demo/car_engine_1.py + :language: python + +``Car`` **creates** an ``Engine`` during its creation. Really? Does it make +more sense then creating an ``Engine`` separatelly and then +**put (inject) it into** ``Car`` when ``Car`` is being created? + +.. literalinclude:: ../../../examples/ioc_demo/car_engine_2.py + :language: python diff --git a/docs/main/introduction/index.rst b/docs/main/introduction/index.rst index fb1773d1..334d16c4 100644 --- a/docs/main/introduction/index.rst +++ b/docs/main/introduction/index.rst @@ -1,12 +1,14 @@ Introduction ============ -Before you have started with *Dependency Injector* framework and dependecy -injection, there are a couple of introduction notes that might be useful. - +Current section of documentation is designed to give some overview about +dependency injection pattern, inversion of control principle and +*Dependency Injector* framework. .. toctree:: :maxdepth: 2 what_is_di di_in_python + key_features + structure diff --git a/docs/main/introduction/key_features.rst b/docs/main/introduction/key_features.rst new file mode 100644 index 00000000..278159e6 --- /dev/null +++ b/docs/main/introduction/key_features.rst @@ -0,0 +1,2 @@ +Key features of Dependency Injector +----------------------------------- diff --git a/docs/main/introduction/structure.rst b/docs/main/introduction/structure.rst new file mode 100644 index 00000000..e6472be5 --- /dev/null +++ b/docs/main/introduction/structure.rst @@ -0,0 +1,2 @@ +Structure of Dependency Injector +-------------------------------- diff --git a/docs/main/introduction/what_is_di.rst b/docs/main/introduction/what_is_di.rst index ae0fda33..02c7909a 100644 --- a/docs/main/introduction/what_is_di.rst +++ b/docs/main/introduction/what_is_di.rst @@ -1,15 +1,15 @@ -What is Dependency Injection? ------------------------------ +What is dependency injection and inversion of control? +------------------------------------------------------ Definition ~~~~~~~~~~ -Wikipedia provides quite good definitions of Dependency Injection Pattern +Wikipedia provides quite good definitions of dependency injection pattern and related principles: .. glossary:: - `Dependency Injection`_ + `Dependency injection`_ In software engineering, dependency injection is a software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (a service). @@ -31,7 +31,7 @@ and related principles: services because these define how the client may use the services. This separates the responsibilities of use and construction. - `Inversion of Control`_ + `Inversion of control`_ In software engineering, inversion of control (IoC) describes a design in which custom-written portions of a computer program receive the flow of control from a generic, reusable library. A software @@ -51,7 +51,7 @@ and related principles: principle, which concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions. - `Dependency Inversion`_ + `Dependency inversion`_ In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships @@ -121,9 +121,9 @@ And `John Munsch`_ provided absolutely Great answer: down to eat. -.. _Dependency Injection: http://en.wikipedia.org/wiki/Dependency_injection -.. _Inversion of Control: https://en.wikipedia.org/wiki/Inversion_of_control -.. _Dependency Inversion: https://en.wikipedia.org/wiki/Dependency_inversion_principle +.. _Dependency injection: http://en.wikipedia.org/wiki/Dependency_injection +.. _Inversion of control: https://en.wikipedia.org/wiki/Inversion_of_control +.. _Dependency inversion: https://en.wikipedia.org/wiki/Dependency_inversion_principle .. _StackOverflow: http://stackoverflow.com/ .. _question: http://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old/1639186 .. _user198313: http://stackoverflow.com/users/198313/user198313 diff --git a/examples/di_demo/ioc_example.py b/examples/di_demo/ioc_example.py index 26568096..2913f028 100644 --- a/examples/di_demo/ioc_example.py +++ b/examples/di_demo/ioc_example.py @@ -1,4 +1,4 @@ -"""The Code, that follows Inversion of Control principle.""" +"""The Code, that follows inversion of control principle.""" class Service(object): diff --git a/examples/ioc_demo/car_engine_1.py b/examples/ioc_demo/car_engine_1.py new file mode 100644 index 00000000..bf6fde9a --- /dev/null +++ b/examples/ioc_demo/car_engine_1.py @@ -0,0 +1,18 @@ +"""Car & Engine example 1.""" + + +class Engine(object): + """Example engine.""" + + +class Car(object): + """Example car.""" + + def __init__(self): + """Initializer.""" + self.engine = Engine() + + +if __name__ == '__main__': + car = Car() + assert car.engine is not None diff --git a/examples/ioc_demo/car_engine_2.py b/examples/ioc_demo/car_engine_2.py new file mode 100644 index 00000000..194506d0 --- /dev/null +++ b/examples/ioc_demo/car_engine_2.py @@ -0,0 +1,18 @@ +"""Car & Engine example 2.""" + + +class Engine(object): + """Example engine.""" + + +class Car(object): + """Example car.""" + + def __init__(self, engine): + """Initializer.""" + self.engine = engine + + +if __name__ == '__main__': + car = Car(Engine()) + assert car.engine is not None