--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/1d2f1399-3310-4b36-ae74-9581a0695002%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
As an experiment, let's just consider the first backwards-incompatible change from the latest release: https://docs.djangoproject.com/en/2.2/releases/2.2/#admin-actions-are-no-longer-collected-from-base-modeladmin-classes ....
With *less* work than currently, except small changes in procedures, we can revive the majority of existing packages (except python2vs3 troubles), ...
Hi Pascal,
I know this is a very late reply, but there have been some things going round my head that I thought I should get down.
First, some positive changes I think we can make from your suggestions:
1. I think in our release notes, for breaking changes that might
need some justification, we should link to the tickets and/or
django-devs discussions behind them. Adding full reasoning in the
notes themselves would likely bloat them far too much, but a link
could be helpful for anything which is not obviously necessary.
2. We should change the wording in our API stability docs, which does indeed initially sound like a promise never to break working code that follows docs:
Django promises API stability and forwards-compatibility since version 1.0.
We do have this line later on:
If, for some reason, an API declared stable must be removed or replaced, it will be declared deprecated but will remain in the API for at least two feature releases. Warnings will be issued when the deprecated method is called.
But we do make changes at a rate faster than that document would make you think.
I suggest that as a contrast to the existing text on that page,
we also point out that we are continually improving Django, and
have a "(eventually) one way to do it" policy regarding how we
plan APIs, which means we will remove old things, while always
providing better alternatives. I'm happy to write a patch for
this.
Second, there were things I wanted to say that might be
useful to you (Pascal) in understanding why you are not likely to
get very far with your current approach.
Your exaggerated tone is not likely to help you. You talk about Django's compatibility breakages as "ruining the day of thousands of anonymous plugin/website maintainers all over the world". When we make these kind of changes, we always do it with very clear and detailed upgrade notes, and almost always with several releases emitting deprecation warnings, as per our policy. And no-one is forced to upgrade immediately. Those who value stability above other things can use LTS, which gives them a 3 year release cadence, not 8 months, which is far from excessively fast compared to other projects.
My involvement in Django these days is primarily not as a core
contributor, but as a user and library maintainer, and I've also
contributed many patches to different 3rd party Django projects to
fix them for Django upgrades. The impression that you give of
Django being a continuously shifting sand is very far from my
experience. The core features and structure of Django have
remained remarkably stable over its history. A few import changes
here and there are very easy to fix (and, more importantly, noisy
and easy to diagnose), and other changes are usually
straightforward. Normally upgrades to libraries I maintain to
support the latest Django version require very little work,
sometimes zero, and often I'm able to support 4 or 5 Django
versions without a problem. Using something like
django-compat-patcher, or some of the other similar libraries,
would add more complexity than the few lines of code I need
otherwise.
Even larger, more complex Django projects like Mezzanine, which use quite a few hacks and internals, are often able to span across two LTS versions.
With all this in mind, it's difficult to see how we are making so many people's lives miserable.
Instead of debating in abstract, or answering your points one by one, I thought a few illustrations might help you see the benefits of Django's approach. The first is the longest, it might be of historical interest to others.I started work on my
first Django project in September 2005, and it went live in
March 2006. It has been running continuously since then - perhaps
by now it can claim to be one of the oldest continuously running
Django sites? I'd be interested to know if anyone can beat it...
Here's a snippet from one of my models.py nearly 14 years ago:
class Message(meta.Model): fromUser = meta.ForeignKey(User, verbose_name="from user", related_name="messageSent" ) toUser = meta.ForeignKey(User, verbose_name="to user", related_name="messageReceived") time = meta.DateTimeField("At") text = meta.TextField("Message") box = meta.PositiveSmallIntegerField("Message box", choices = MESSAGE_BOXES) def __repr__(self): #return str(self.id) return "[" + str(self.id) + "] to " + repr(self.get_toUser()) + " from " + repr(self.get_fromUser()) class META: admin = meta.Admin( list_display = ('toUser', 'fromUser', 'time') ) ordering = ('-time',)
Wow, just look at that! ORM stuff under a `meta` namespace. Admin options stored under the model META inner class. These funky `get_XXX()` accessors for related fields. (Not to mention my naming conventions and code formatting back then...) While I have memories of some of the big changes in syntax that happened pre 1.0, I had no memory that we use to do most of these things. Why? Because this project no longer does it this way. My brain thankfully reclaimed the space taken up by these old ways of doing things. If we developed Django according to the backwards compatibility philosophy you are suggesting, that would not have happened. Instead, my code would be just as bad/quirky today as was did back then, for two reasons:
1. Without being forced to upgrade, I probably wouldn't have done.
2. If Django devs had needed to keep supporting old ways of doing things for long periods of time, two things could have happened:
When I work on this old project I find:
1. It is virtually indistinguishable from brand new Django code.
2. The code quality has improved over time, and the project
has never been in better shape than now.
I have none of that "Oh no I've got to fix that old project, how did we use to do this stuff again?" feeling. This project is a breeze to work with, and feels completely modern. If I needed to pass it on to someone else, I would be less worried now about doing so than I ever have been. How many other 14 year old projects can you say such things about?
I could multiply examples. Take URLs. Here's the old code:
from django.conf.urls.defaults import * urlpatterns = patterns('cciw.apps.cciw.views', (r'^thisyear/$', 'camps.thisyear'), (r'^camps/$', 'camps.index'), (r'^camps/(?P<year>\d{4})/?$', 'camps.index'), (r'^camps/(?P<year>\d{4})/(?P<number>\d+)/?$', 'camps.detail'), (r'^sites/$', 'sites.index'), (r'^sites/(?P<name>.*)/$', 'sites.detail'), (r'', 'htmlchunk.find') )
Versus the current code:
from django.urls import path from cciw.cciwmain.views import camps as camp_views from cciw.cciwmain.views import sites as sites_views urlpatterns = [ # Camps path('thisyear/', camp_views.thisyear, name="cciw-cciwmain-thisyear"), path('camps/', camp_views.index, name="cciw-cciwmain-camps_index"), path('camps/<yyyy:year>/', camp_views.index, name="cciw-cciwmain-camps_year_index"), path('camps/<yyyy:year>/<slug:slug>/', camp_views.detail, name="cciw-cciwmain-camps_detail"), # Sites path('sites/', sites_views.index, name="cciw-cciwmain-sites_index"), path('sites/<slug:slug>/', sites_views.detail, name="cciw-cciwmain-sites_detail"), # ... ]
There are many improvements, for example:
Everything is simpler and more Pythonic - while at the same time
the fundamental structure and abstractions are extremely similar,
and every migration has been straightforward. It is unfortunate
that we didn't have a crystal ball in order to optimize these
migrations a bit more, or indeed get it right from the start. But
that's life, we don't have crystal balls.
All of the changes with URLs have had thought through reasons.
Often the changes fix issues that newbies consistently trip over
(based on feedback from people who do a lot training of new Django
users) and security issues we've had.
You mentioned PHP and Wordpress, and I would agree that their
approach is quite different. But it also comes with huge costs.
Thankfully I already wrote a blog post that covers pretty much
everything I want to say, with quite a few comparisons to Django:
https://lukeplant.me.uk/blog/posts/wordpress-4.7.2-post-mortem/
A zero day vulnerability in which your web site gets defaced and possibly fully hacked is what I think of when I hear the phrase "my day was ruined", and that is the kind of vulnerability we've so far been able to avoid in Django.
Critical security vulnerabilities like the above are also just the tip of the iceberg - the same issues that cause them also cause all kind of bugginess which hurt you in much more every-day ways, but these costs add up.
I'm surprised you let AngularJS off the hook so lightly. One of
my clients has a project with 25,000 lines of AngularJS code.
Having looked at the detailed upgrade instructions, in the context
of our application the first step essentially amounts to "first
re-write your entire app" (to use components everywhere, which we
are not). There are entire books
devoted to this upgrade, it is a massive undertaking that requires
a deep understanding of both AngularJS and Angular. The team is
considering ditching everything and starting with a new framework.
This is the kind of situation that leaves businesses in very bad
situations, having to choose between either being able to
deliver new features for the next six months to a year or
rewriting and paying off the technical debt.
For my past and current clients, and all my side projects, I have never faced anything remotely closely to that choice with Django. Sure, we've had to schedule in some time for upgrades, especially if we've had a lot of dependencies, but doing the upgrades, and fixing most of the deprecation warnings too, for small to medium sized projects, usually has been work on the scale of hours, sometimes days — maybe a week of development work if we were ahead of the curve in terms of upgrading and had to submit patches to lots of 3rd party dependencies. But never months — never anything close to "senior management needs to get involved with this decision".
To sum up, Django has so far avoided the huge upgrade
costs of something like AngularJS. We've never reached the stage
where we've thought "It's too awful, we'll have to start again",
and never had to write that blog post - exactly the kind of news
which might indeed ruin your day as a web developer or project
manager.
This might have been luck at choosing the right abstractions while
AngularJS had some bad luck, but whatever the explanation, it's a
great thing. At the same time we've avoided the horrors of a
codebase like Wordpress which has just kept going with layer upon
layer of cruft. Old Django projects (that have been maintained),
and the Django code base itself, remain a pleasure to work with.
That's also why we're able to attract excellent developers, like
our current Django Fellows, so that Django continues to improve.
And we're not done yet - Django appears to have quite a bit of life left it in still! I'm convinced that all of this has been due to it's approach to improvement, gradual backwards compatibility breakages, and not tolerating previous bad design, rather than despite it.
Hope that helps,
Luke
Hi Pascal,
I know this is a very late reply, but there have been some things going round my head that I thought I should get down.
First, some positive changes I think we can make from your suggestions:
1. I think in our release notes, for breaking changes that might need some justification, we should link to the tickets and/or django-devs discussions behind them. Adding full reasoning in the notes themselves would likely bloat them far too much, but a link could be helpful for anything which is not obviously necessary.
2. We should change the wording in our API stability docs, which does indeed initially sound like a promise never to break working code that follows docs:
Django promises API stability and forwards-compatibility since version 1.0.
We do have this line later on:
If, for some reason, an API declared stable must be removed or replaced, it will be declared deprecated but will remain in the API for at least two feature releases. Warnings will be issued when the deprecated method is called.
But we do make changes at a rate faster than that document would make you think.
I suggest that as a contrast to the existing text on that page, we also point out that we are continually improving Django, and have a "(eventually) one way to do it" policy regarding how we plan APIs, which means we will remove old things, while always providing better alternatives. I'm happy to write a patch for this.
Second, there were things I wanted to say that might be useful to you (Pascal) in understanding why you are not likely to get very far with your current approach.
Your exaggerated tone is not likely to help you. You talk about Django's compatibility breakages as "ruining the day of thousands of anonymous plugin/website maintainers all over the world". When we make these kind of changes, we always do it with very clear and detailed upgrade notes, and almost always with several releases emitting deprecation warnings, as per our policy. And no-one is forced to upgrade immediately. Those who value stability above other things can use LTS, which gives them a 3 year release cadence, not 8 months, which is far from excessively fast compared to other projects.
Instead, my code would be just as bad/quirky today as was did back then, for two reasons:
1. Without being forced to upgrade, I probably wouldn't have done.
There are many improvements, for example:
- Star imports have been removed. There are lots of good reasons why every Python code linter complains about these. Or would you rather still have them?
- In my editor I can put my cursor on a view function like `index`, do "jump to definition" and it does the right thing, because it is normal Python. Do you think dotted strings were better?
- My list of URLs is just a list, and can be manipulated with normal list methods and functions (which I often need to do). Do you think wrapping everything in `patterns()` would be an improvement? For the sake of an extensibility we might just use someday (though we didn't in well over a decade)?
- The addition of `path` is a great help, and has really cleaned up URL handling a ton, and even more in other areas of my project. I wasn't forced to make this change, but it's a great improvement. However, this is the kind of big addition that the Django developers only considered and were able to do because the Django codebase was not a pile of backwards compatibility hacks and cruft already. And yes, doing so meant we lost some undocumented classes which were implementation details, which you also seem to be complaining about.
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/3adb7b80-c750-4cf9-95df-128f9f6fe7cc%40googlegroups.com.
Pascal, you can read about the reason for the action actions change on the ticket https://code.djangoproject.com/ticket/29917 ...and on this mailing list... https://groups.google.com/d/topic/django-developers/-OWoYL_zryM/discussion. I hesitate to link to things like that in the release notes because the discussions can be long and somewhat difficult to follow. Rather, as appropriate, I tried to include a short summary of the rationale for backwards incompatible changes in the release notes.In my years working on Django, I found it reasonable to occasionally make backwards incompatible changes if there's a consensus that a deprecation isn't feasible or worthwhile. Sometimes practicality beats purity, in my experience.Luke's experience and views parallel mine. I think the current deprecation cycle works well.
I have had a short reply sitting in draft status for a while but not found the energy to read all of your posts.I'd just like to chime in and echo the sentiment from Aymeric, Florian, Luke, and Tim. I worked with Django for nearly 5 years before being accepted onto the core team.One of the main tasks I've done in my career has been upgrading Django - I did a recent count and I've done it at least 10 times on major applications (100k+ lines). Upgrading Django has always been easy in comparison with other changes. The Django upgrade process is miles above other Python packages, which often miss changelogs let alone use standardized versioning. I've always found the backwards incompatible changes in Django improve my project's code standards incrementally (as Luke said).When reviewing features in Django I've normally erred towards putting everything through the deprecation cycle only to discuss it with other developers and decide it's not worth it. Practicality beats purity as Tim says.
The relative stability of Django is one of the things that attracted me to it and continues to keep me here, working on it and recommending it to others.
--
On 17 Aug 2019, at 18:21, Pkl <chambon...@gmail.com> wrote:In just 5 lines of discussion...
some wild guess / wishful thinking
what is practical for core developers is NOT the same as what is practical for users
even if it means creating a task force just for keeping a slight eye on compatibility shims
All that to face red herrings
*your* little version of Django
Punishing users
Just for the record, we spent a good time discussion this change (to bring inheritance of Admin Actions in line with Python’s expected inheritance rules). We reviewed the entire history of the feature. We explored an alternative approach, which would have maintained BC. We put the discussion to the mailing list, where further people reviewed it, and we came to a decision, as a group, without any objections being raised.
Tech debt is a very real thing. Keeping it under control is vital to the pace of improvement and updates for any project, large, middling or small. Any project requires maintanence at minimum, just like owning a car or house. If you buy a car and run it every day for five years, only filling up the gas tank and adding a splash of oil now and then, you don't have any excuse to be upset at the mechanic or manufacturer for the size of the repair bill when things start breaking. At least with software, its alot easier to get fixes out than with hardware. You make a persuasive argument and have great passion, but the overall goal of enabling out of date and unsupported releases to remain around longer than they should be makes me feel really uncomfortable. A spftware project is not buy once and forget, neither is a car. And your package seems to encourage that lax practice to a level that I would be highly resistant at working at a company if I couldn't persuade management to prioritize keeping up to date and tech debt at a manageable level.
As we're getting to the end of useful arguments here, I'd like to ask you to step back for a minute and take a calm look at what you're writing. Imagine you were receiving such messages rather than sending them. Would you want to spend more time collaborating with the person addressing you that way and to receive more such messages? Perhaps this is another reason why you aren't getting as much support as you'd hope.
For example, Luke was open to amending the deprecation policy to better reflect reality. You should have suggested some concrete changes, erring on the side of caution. Instead you chose to repeat the same argument, except more agressively. This doesn't get us any closer to a documentation patch. In fact this reduces the likelihood that someone will choose to spend time writing that patch.
--
You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/GgqjkYSqfR0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/6b6f6b14-c3cc-4ba9-9d77-92ecaab23e11%40googlegroups.com.