summaryrefslogtreecommitdiff
path: root/artima
diff options
context:
space:
mode:
authormicheles <micheles@micheles-mac>2010-03-28 17:42:39 +0200
committermicheles <micheles@micheles-mac>2010-03-28 17:42:39 +0200
commitecf277c15bda9e6284c2fff02ae5917e7ce159f2 (patch)
tree455e08c6c7d29712573e9d9dfde19ed633ad391e /artima
parentaa7077b22aa020b53264ad1bca0f8ba82b25348d (diff)
downloadmicheles-ecf277c15bda9e6284c2fff02ae5917e7ce159f2.tar.gz
Recovered my repository
Diffstat (limited to 'artima')
-rw-r--r--[-rwxr-xr-x]artima/general/eeepc.txt0
-rw-r--r--artima/general/enterprise.txt150
-rw-r--r--artima/notes/links-and-citations.txt16
-rw-r--r--[-rwxr-xr-x]artima/python/expert-python-programming.txt0
-rw-r--r--artima/python/super4.py136
5 files changed, 183 insertions, 119 deletions
diff --git a/artima/general/eeepc.txt b/artima/general/eeepc.txt
index 8039ff0..8039ff0 100755..100644
--- a/artima/general/eeepc.txt
+++ b/artima/general/eeepc.txt
diff --git a/artima/general/enterprise.txt b/artima/general/enterprise.txt
index bc9c5de..d4102b2 100644
--- a/artima/general/enterprise.txt
+++ b/artima/general/enterprise.txt
@@ -1,69 +1,104 @@
Enterprise programming means working with legacy code
===========================================================
-In a recent thread on Artima people argued about the productivity
-differences between working on a startup company and working in an
-old-fashioned enterprise company. Some people ascribe the improved
+In a recent thread on Artima, solicited by a `post of Tim Bray`_, people
+argued about the productivity differences between startups and
+old-fashioned companies. Some programmers, like Bray, ascribe the improved
productivity we see in startups to the methodology which is typically
in such enviroments, in particular the reliance on Agile methods; on
the other side some people question such analysis.
I am also skeptical: it looks plain obvious to me that the reason why
-startups are so productive is not (much) the methodology they use, is the
-fact that they work mostly with new code whereas traditional
-enterprises mostly work with old code. That made most of the
-difference. Of course, the methology has its relevance, but I would
-say that it is not the most important parameter. My claim is that
-working with legacy code in an enterprise context is inherently more
-difficult than working with new code in a startup context, and that is
-independent from the methodology: even if the best of the possible
-cases, when you have a code base in good shape, in any case a company
-will have millions of lines of code written by developers which are no
-more there, answering requeriments that nobody remembers,
-whereas a startup (being born only recently, by
-definition) will have much less code and it will very likely be code
-written by the developers working there for customers which are still
-actively using the software.
+startups are so productive is not (much) the methodology they use, is
+the fact that they work mostly with *new* code. On the other hand, traditional
+enterprises mostly work with *old* code: this fact alone makes most of
+the difference. Of course, the methology has its relevance, but I
+would say that it is not the most important parameter. My claim is
+that working with legacy code in an enterprise context is inherently
+more difficult than working with new code in a startup context, and
+that is independent from the methodology: even if the best of the
+possible cases, when you have a code base in good shape, the situation
+is never favorable to the traditional company. The usual case for the
+company is to have millions of lines of code written by developers
+which are no more there, answering requeriments that nobody
+remembers. On the other hand, the startup - being born only recently,
+by its very definition - will have much less code and it will very
+likely be code written by the developers working there for customers
+which are still actively using the software.
-It should not be necessary to state the obvious, but perhaps there a few things
-which are not obvious to people that never worked in an enterprise context.
-Here by "enterprise" I will mean any company which has a (possibly long)
-history and a significant number of developers. The company were I work
-is only 10 years old the total number of developers who work or worked there
-is only 15: still, we have a lot of the troubles of enterprise programming
-and I can imagine what is going on in larger and older companies.
+It should not be necessary to state the obvious, but perhaps there are
+a few things which are not obvious to people that never worked in an
+enterprise context. Here by "enterprise" I will mean any company
+which has a (possibly long) history and a significant number of
+developers. The company were I work is only 10 years old the total
+number of developers who work or worked there is under 20: still, we
+have a lot of the troubles of enterprise programming and I can imagine
+what is going on in larger and older companies. When I worked in a
+startup I had no idea of what it meant to work with legacy code.
+Actually I started my programming career as a hobbyist: at the time
+I was just programming for personal projects, for
+the learning experience and to simplify my daily life with a few
+scripts. I was the only developer for such projects, I did not use a
+Version Control System and everything went smoothly and fine. Old code
+was just thrown away, libraries were written with time and ease, I had
+no time constraints and no problems at all. My productivity rocked.
-In can split my programming career in three phases:
+Later on, I entered professionally in the field and I was hired as
+a consultant in a startup. In such occasion I started doing pair programming
+and I learned a lot of things. Still, all of my code was new code, i.e.
+I had not to read other people code,
+except for what concerns the framework we used. And then the trouble
+lied, since the framework (Zope) was large and complex. I learned the
+whole Python and its standard library in a few months: but learning
+Zope and Plone would require a few years. This is the first difficulty
+of working in an enterprise world, having to learn enterprise-oriented
+frameworks with all their problems. Still, this is not yet working in
+an enterprise. The big problem, when you work as an enterprise developer,
+is that on top of studying
+third party software, you have to study *a lot* of internal software.
+Whereas frameworks released in the open are intended for third party
+consumption and are somewhat polished (sometimes this is not really
+true, but let it pass), code written for internal usage is
+typically dirty, less documented and well structured
+being written under time constraints. And there all
+the difficulty of working in an enterprise enters in the game. (of
+course, there are also other difficulties related to company policies
+and politics, which may be much more serious than coding-related
+issues but here I will focus only on the programming-related aspects).
- - solo scripter
- - startup developer
- - enterprise developer
+In companies with an history, you never start from scratch: even new
+projects live in a pre-existing ecosystem and must be written by
+knowning how do they relate to the rest of the world. And there aren't
+many new projects anyway. Nearly all projects are refactoring and
+extensions of code which is already there and which is usually old,
+difficult to understand, often obsolete in some parts, and nearly
+always insufficiently documented.
-In the first phase I was just programming for personal projects, for
-the learning experience and to simplify my daily life with helper
-scripts. I was the only developer for such projects, I did not use a
-Version Control System and everything went smoothly and fine. Old code
-was just thrown out, libraries were written with time and ease, I had
-no time constraint and no problems at all. My productivity rocket. In
-the second phase I worked at a startup. All my code was new code, i.e.
-I had not to read other people code, except for what concerns the
-framework we used. And then the trouble lied, since the framework
-(Zope) was large and complex. I learned the whole Python and its
-standard library in a few months: but learning Zope and Plone would
-require a few years. This is the first difficulty of working in an
-enterprise world, having to learn enterprise-oriented frameworks with
-all their problems. Still, this is not yet working in an
-enterprise. When I started working as an enterprise developer, on top
-of studying third party software, I had to study our internal
-software, which is much bigger and much less documented and well
-structured. The reason is that frameworks released in the open are
-intended for third party consumption and are somewhat polished
-(sometimes this is not really true, but let it pass), whereas code
-written for internal usage is typically dirty. And there all the
-difficulty of working in an enterprise enters in the game. (of course, there are
-also other difficulties related to company policies and politics,
-which may be much more serious than coding-related issues but here I
-will focus only on the programming-related aspects).
+This is the *natural* state of the affairs: I actually think that
+whereas it is important to keep a certain level of sanity in the code
+one writes, one should accept a certain level of uncleaness as
+natural. For instance, in our context business requirements change so
+often that it would not make sense to write more documentation,
+because then we would have the problem of outdated documentation,
+which is worse than no documentation. Also, if the company is healthy
+there should always be more things to do than people, so that there is
+not much time to cure old code, unless there is a business requirement
+to do so. Often we write code for a specific client: in such a
+situations there are two possible outcomes: we sell the same service
+to other customers - in that case we refactor and clean up the
+original code - or the original client closes the contract - in that
+case then we remove the code. It makes no business sense to spent too
+much time in writing code that could be removed after a year, whereas
+it makes sense to refactor it if we are going to reuse it for another
+paying customer.
+
+I started working at my current company with the charge of maintaing an
+old Zope project; I am still maintaining it after more than four years,
+even if we want to dismiss the Zope tecnology. Over the years I have
+ported most of the code to a new platform, but the parts which are
+exposed to the customers are still running on the Plone site and they
+will probably stay there because it works and there is nearly no
+maintenance to perform (just add a new customer once in a while).
Let me be concrete: I have been spending the latest two months in a
large refactoring project (which is only at the beginning, anyway) so
@@ -72,11 +107,12 @@ developer is facing every day.
-
+ because it was written with specs which are not valid anymore
.. http://www.michaelfeathers.com/
.. Working Effectively with Legacy Code
-
+.. _post of Tim Bray:
+
.. persone a StatPro
1 Adolfo
@@ -94,3 +130,5 @@ developer is facing every day.
13 Silvia
14 Andrea
15 Paolo
+ 16 Tipo a Udine
+ 17 Tipo libanese
diff --git a/artima/notes/links-and-citations.txt b/artima/notes/links-and-citations.txt
index 38b31f6..5d80ca0 100644
--- a/artima/notes/links-and-citations.txt
+++ b/artima/notes/links-and-citations.txt
@@ -41,3 +41,19 @@ productively is, in some sense, incidental. -- George Neuner on c.l.s.
I think one good outcome of R6RS is that library writers form a
bridge between implementors who would not be collaborating otherwise -- Aziz
+
+Enterprise Scale
+------------------
+
+In talking with a sysadmin about installs, it occurred to me what the working definition of Enterprise Scale is
+
+ The install is not "next-next-done" wizard
+
+
+Desktop and "departmental" applications have easy-to-use installers with few options and simple configurations.
+
+Enterprise applications do not have installers and have configurations so complex and terrifying that it takes numerous specialists (Sysadmins, DBA's, programmers, managers, business analysts and users) to install and configure the application.
+
+That's how we know that a LAMP-based application stack involving Python can't be enterprise-ready. Python and MySQL install with "next-next-done" wizards. The application suite installs with a few dozen easy_install steps followed by a database build script.
+
+Anything that simple can't scale. *S.Lott*
diff --git a/artima/python/expert-python-programming.txt b/artima/python/expert-python-programming.txt
index c5adf2a..c5adf2a 100755..100644
--- a/artima/python/expert-python-programming.txt
+++ b/artima/python/expert-python-programming.txt
diff --git a/artima/python/super4.py b/artima/python/super4.py
index 9b1d229..024fcf2 100644
--- a/artima/python/super4.py
+++ b/artima/python/super4.py
@@ -1,20 +1,18 @@
"""\
-Most languages supporting inheritance support cooperative inheritance too,
+Most languages supporting inheritance support cooperative inheritance,
i.e. there is a language-supported way for children methods
-to dispatch to their parent method. Cooperation is usually implemented via a
+to dispatch to their parent method: this is usually done via a
``super`` keyword. Things are easy when the language support single
inheritance only, since each class has a single parent and there is an
unique concept of super method. Things are difficult when the
-language support multiple inheritance: in that case there is no
-meaningful concept of super class and of super method, but the programmer
-has to understand the intricacies of so-called Method Resolution Order.
+language support multiple inheritance: in that case the programmer
+has to understand the intricacies of the Method Resolution Order.
Why cooperative hierarchies are tricky
--------------------------------------------
-This paper is intended to be very practical, so I will explain
-cooperative multiple inheritance with an example. Consider the
-following hierarchy (in Python 3):
+This paper is intended to be very practical, so let me start with an example.
+Consider the following hierarchy (in Python 3):
$$A
$$B
@@ -29,36 +27,35 @@ will call ``super().__init__()`` in ``A.__init__`` at some point: the
tricky point is to understand which method will be called
for *indirect* instances of ``A``.
-In a single inheritance language there would be an unique answer both
-for direct and indirect instances (``object`` is the super class of
-``A`` and ``object.__init__`` is the method called by ``super().__init__()``)
-but in a multiple inheritance language there is no easy answer. It is
-better to say that there is no super class and it is impossible to
-know which method will be called by ``super().__init__()`` unless the
-entire hierarchy is known in advance. In this case let us assume that
-the entire hierarchy is known (i.e. there are no other subclasses
-defined in other modules). In particular, this is what happens when we
-instantiate ``C``:
+In a single inheritance language there is an unique answer both for
+direct and indirect instances (``object`` is the super class of ``A``
+and ``object.__init__`` is the method called by
+``super().__init__()``). On the other hand, in a multiple inheritance
+language there is no easy answer. It is better to say that there is no
+super class and it is impossible to know which method will be called
+by ``super().__init__()`` unless the subclass from wich ``super`` is
+called is known. In particular, this is what happens when we instantiate ``C``:
>>> c = C()
C.__init__
A.__init__
B.__init__
-As you see the super call in ``C`` dispatches to ``A.__init__`` and the super
-call there dispatches to ``B.__init__`` which in turns dispatches to
-``object.__init__``. Therefore *the same super call can dispatch to different
-methods*: when ``super().__init__()`` is called directly by instantiating
+As you see the super call in ``C`` dispatches to ``A.__init__`` and then
+the super call there dispatches to ``B.__init__`` which in turns dispatches to
+``object.__init__``. The important point is that
+*the same super call can dispatch to different methods*:
+when ``super().__init__()`` is called directly by instantiating
``A`` it dispatches to ``object.__init__`` whereas when it is called indirectly
by instantiating ``C`` it dispatches to ``B.__init__``. If somebody
extends the hierarchy, adds subclasses of ``A`` and instantiated them,
then the super call in ``A.__init__``
can dispatch to an entirely different method: the super method call
depends on the instance I am starting from. The precise algorithm
-specifying the order in which the methods are called by ``super`` is
-called the Method Resolution Order algorithm, or MRO for short and it
-is discussed in detail in an old essay I wrote years ago.
-Interested readers are referred to it.
+specifying the order in which the methods are called is
+called the Method Resolution Order algorithm, or MRO for short. It
+is discussed in detail in an old essay I wrote years ago and
+interested readers are referred to it (see the references below).
Here I will take the easy way and I will ask Python.
Given any class, it is possibly to extract its linearization, i.e. the
@@ -114,14 +111,16 @@ When you design a hierarchy you will expect for instance that
``A.__init__`` will call ``B.__init__``, but adding classes (and such
classes may be added by a third party) may change the method chain. In this
case ``A.__init__`` (when invoked by an ``F`` instance) will call
-``D.__init__``: if the behavior of your code depends on the ordering of the
+``D.__init__``. This is dangerous: for instance,
+if the behavior of your code depends on the ordering of the
methods you may get in trouble. Things are worse if one of the methods
-in the cooperative chain does not have a compatible signature.
+in the cooperative chain does not have a compatible signature, since the
+chain will break.
This problem is not theoretical and it happens even in very trivial
hierarchies. For instance, here is an example of incompatible
-signatures in the ``__init__`` method (this affects even Python 2.6,
-not only Python 3.X):
+signatures in the ``__init__`` method (this problem
+affects even Python 2.6, not only Python 3.X):
.. code-block:: python
@@ -143,13 +142,14 @@ introduce ``Z`` you get in trouble since ``super().__init__(a)`` in
turns will call ``Y.__init__`` with no arguments, resulting in a
``TypeError``! In older Python versions (from 2.2 to 2.5) such
problem can be avoided by leveraging on the fact that
-``object.__init__`` accepts any number of arguments (ignoring them) and
-thus replacing ``super().__init__()`` with ``super().__init__(a)``. In Python
+``object.__init__`` accepts any number of arguments (ignoring them), by
+replacing ``super().__init__()`` with ``super().__init__(a)``. In Python
2.6+ instead there is no real solution for this problem, except avoiding
``super`` in the constructor or avoiding multiple inheritance.
-In general you should use ``super`` only when all the
-cooperative methods have consistent signature: that means that you
+In general if you want to support multiple inheritance you should use
+``super`` only when the methods in a cooperative chain
+have consistent signature: that means that you
will not use super in ``__init__`` and ``__new__`` since likely your
constructors will have custom arguments whereas ``object.__init__``
and ``object.__new__`` have no arguments. However, in practice, you may
@@ -174,7 +174,7 @@ Even if ``super`` has its shortcomings, there are meaningful use cases for
it, assuming you think multiple inheritance is a legitimate design technique.
For instance, if you use metaclasses and you want to support multiple
inheritance, you *must* use ``super`` in the ``__new__`` and ``__init__``
-methods: there is no problem in doing so, since the constructor for
+methods: there is no problem, since the constructor for
metaclasses has a fixed signature *(name, bases, dictionary)*. But metaclasses
are extremely rare, so let me give a more meaningful example for an application
programmer where a design bases on cooperative
@@ -196,9 +196,8 @@ and two concrete classes ``DbManager`` and ``FtpManager``:
$$DbManager
$$FtpManager
-Now suppose you need to manage both a database and an FTP site and suppose that
-you think multiple inheritance is a good idea: then you can define a
-``MultiManager`` as follows:
+Now suppose you need to manage both a database and an FTP site:
+then you can define a ``MultiManager`` as follows:
$$MultiManager
@@ -219,12 +218,12 @@ method ``getinfolist`` calling ```DbManager.getinfolist`` and
$$close
$$getinfolist
-This would less elegant but probably clearer and safer so you can always
+This would be less elegant but probably clearer and safer so you can always
decide not to use ``super`` if you really hate it. However, if you have
``N`` common methods, there is some boiler plate to write; moreover, every time
you add a ``Manager`` class you must add it to the ``N`` common methods, which
is ugly. Here ``N`` is just 2, so not using ``super`` may work well,
-but in general it is clear that the cooperative approach is more elegant.
+but in general it is clear that the cooperative approach is more effective.
Actually, I strongly believe (and always had) that ``super`` and the
MRO are the *right* way to do multiple inheritance: but I also believe
that multiple inheritance itself is *wrong*. For instance, in the
@@ -235,11 +234,11 @@ such as the following:
$$MyMultiManager
There are languages that do not provide inheritance (even single
-inheritance!) and are perfectly fine, so you should keep an open
-mind. There are always many options and the design space is rather
-large. Personally, I always use ``super`` but I use
-single-inheritance only, so that my cooperative hierarchies are
-trivial.
+inheritance!) and are perfectly fine, so you should always question
+if you should use inheritance or not. There are always many options
+and the design space is rather large. Personally, I always use
+``super`` but I use single-inheritance only, so that my cooperative
+hierarchies are trivial.
The magic of super in Python 3
----------------------------------------------------------------------
@@ -273,7 +272,7 @@ the first argument of the current method is ``self``, but it may be
Since ``super()`` knows the class it is invoked from and the class of
the original caller, it can walk the MRO correctly. Such information
is stored in the attributes ``.__thisclass__`` and ``.__self_class__``
-and you may understand how it works with the following example:
+and you may understand how it works from the following example:
$$Mother
$$Child
@@ -284,8 +283,8 @@ $$Child
<class '__main__.Mother'>
<class '__main__.Child'>
-Here ``.__self__class__`` is just the clas<s of the first argument (``self``)
-but this not always the case. The exception is the case of classmethods and
+Here ``.__self__class__`` is just the class of the first argument (``self``)
+but this is not always the case. The exception is the case of classmethods and
staticmethods taking a class as first argument, such as ``__new__``.
Specifically, ``super(cls, x)`` checks if ``x`` is an instance
of ``cls`` and then sets ``.__self_class__`` to ``x.__class__``; otherwise
@@ -308,10 +307,8 @@ argument:
__selfclass__ <class '__main__.C2'>
called classmethod C0.c
-So take care that ``__selfclass__`` is not the class of ``self``, if ``self``
-is a subclass of ``__thisclass__``.
-There is a lot of magic going on, and even more. For instance, this
-is a syntax that cannot work:
+There is a lot of magic going on in Python 3 ``super``, and even more.
+For instance, this is a syntax that cannot work:
$$super_external
@@ -324,32 +321,45 @@ syntax, by writing the external method as
$$__init__
-everything will work because we are explicitly telling than the method
+everything will work because you are explicitly telling than the method
will be attached to the class ``C``.
-There is also a wart of Python 3, pointed out by `Armin Ronacher`_ and
-others: the fact that ``super`` should be a keyword but it is
-not. Therefore horrors like the following are possible:
+I will close this section by noticing a wart of ``super`` in Python 3,
+pointed out by `Armin Ronacher`_ and others: the fact that ``super``
+should be a keyword but it is not. Therefore horrors like the
+following are possible:
$$super_horrors
DON'T DO THAT! Here the called ``__init__`` is the ``__init__`` method
-of the object ``None``!!
-
-Also, ``super`` is special and it will not work if
+of the object ``None``!!
+
+Of course, only an evil programmer would shadow ``super`` on purpose,
+but that may happen accidentally. Consider for instance this use case:
+you are refactoring an old code base written before the existence of
+``super`` and using ``from mod import *`` (this is ugly but we know
+that there are code bases written this way), with ``mod`` defining a
+function ``super`` which has nothing to do with the ``super``
+builtin. If in this code you replace ``Base.method(self, *args)`` with
+``super().method(*args)`` you will introduce a bug. This is not common
+(it never happened to me), but still it is bug that could not happen if
+``super`` were a keyword.
+
+Moreover, ``super`` is special and it will not work if
you change its name as in this example:
.. code-block:: python
- # see http://lucumr.pocoo.org/2010/1/7/pros-and-cons-about-python-3
+ # from http://lucumr.pocoo.org/2010/1/7/pros-and-cons-about-python-3
_super = super
class Foo(Bar):
def foo(self):
_super().foo()
-This is unfortunate, since we missed the opportunity to make it a keyword
-in Python 3, without good reasons (Python 3 was expected to break compatibility
-anyway).
+Here the bytecode compiler will not treat specially ``_super``, only
+``super``. It is unfortunate that we missed the opportunity to make ``super``
+a keyword in Python 3, without good reasons (Python 3 was expected
+to break compatibility anyway).
References
---------------------------------------