cessor
Joined 12 years ago
Joined 12 years ago
> My real criticism of Django is that, at long last, I think it's starting to look dated.
Actually, that is something I found really great about django. I found that django is reliable over a long period of time. The js/node/react/express/angular apps I had developed in the past (~2012+) can't be built these days without redoing major components. I never had these problems with django.
As for the responsiveness of the results, I found that a good understanding of django's performance helps. Using a good caching strategy (on models, views + nginx) yields results have almost instant reactions, even though there is the whole HTTP to HTML roundtrip. While they do have the noticable page-reload semantics, I found that these are way easier to build and sometimes yield very enjoyable experiences for my users. After all, I'm not building a YouTube so PictureInPicture and SPA-semantics aren't that important to my users.
> Modern web apps are maintaining models in the client and staying current though a combination of ajax queries and websockets.
Julia Elman explains how to do this with Django + DRF and Backbone.js in the book "Lightweight Django" (O'Reilly). Is this a viable compromise?
I found that django's naming scheme for migrations is good enough; here are some real ones that I pulled out of my current project:
migrations/0006_add_modeltranslation.py
migrations/0007_remove_temp_fields.py
migrations/0008_remove_language_field.py
migrations/0009_alter_page_slug.py
migrations/0010_alter_menuitem_absolute_url.py
While they aren't semantically rich ('Why did you change absolute url on menu item?') I found that they are easy to distinguish and navigate.1. Relying on implicit SQL queries
2. Using the default User model
3. Using automatic migration names
4. Relying on automatic database table names
5. Using multiple tiny apps
6. Dumping apps in the root directory
I wouldn't call those harmful. Most are non-issues, while others are "unfortunate" at best.
1. I found that the ORM works quite well and it's easy to optimize later. Using `prefetch_related` or `select_related` in the ORM still feels weird (they're just joins), but I wouldn't call them harmful.
2. I found it unfortunate that the info on how to change the User model is hidden so deep in the Documentation. I don't like to RTFM, but with Django it sure is worth it; same goes for 1.
3. I occasionally do it, but most of the time, I don't and never had an issue.
4. It do rely on that and found django's naming scheme to be a non-issue. I guess this might be more important if you need to change your database out of band (out of django band, that is)
5. This point is unsubstantiated. Apps aren't mere packages but also define a scope for the admin tool (which I use a lot and think is an integral part of Django) so that it will group models and allow individual access (i.e. apps also provide scope for your permissions). I use tons of apps but I wouldn't call it a harmful default.
6. Yeah, dynamic languages might produce naming collisions. Still beats imports like `org.example.publib.boulder.yourmoms.maidenname.models.impl.Account`
Professionalism means being able to produce convergent results given varying resources, but when the spec is unclear, your employer doesn't provide appropriate resources for you to perform or if your mental health is in danger, I think it's perfectly valid to back off. "Professional" does not mean "sorcerer". A professional photographer can't take a good picture in complete darkness, and even a good architect can't create a distributed system when the environment won't support it. It argue it's professional to know your own limits and reject a job offer.
It's difficult to make the decision to leave, especially when you have been jobhunting for a while and I can't say anything substantial on how anyone should make such a decision, but the other day I found a meme saying (something along those lines):
In a job, you should either earn or learn; either is good, both is ideal, if it's neither: leave. If the job pays ok money, but costs your sanity, I'd argue you should leave.
Some of the criticism is really superficial:
function createEmployee(firstName, lastName) {
return {
firstName: firstName,
lastName: lastName,
};
}
OO-Programs have these weird factory functions called constructors that do exactly that. To me, it makes sense that such functions should share their living space with the class that they are creating. Where else would you like to put these functions? "Utils"?As for classes, namespaces and objects: as others have pointed out, this is an implementation detail. In Python, for example, classes are objects. Besides, classes and objects are functions (and the other way around) so it doesn't matter all that much in practice.
What buggs me more is code like this:
class SayHello {
public static void toPerson(String name) {
System.out.println("Hello " + name);
}
}
Sure, comparing it to an empty Python file which just says "print" this looks like an aweful lot of code. However if the paradim is poorly understood, it will seem to be working against you: class Name {
public Name (string name) {
this.name = name;
}
public static void greet() {
System.out.println("Hello " + this.name);
}
}
The programming is different in that you create a declarative network of objects that then ... act. At this level, there is hardly any difference, except that the name has been introduced as a proper concept. Many people will argue that such value objects are expensive or inefficient (which they are) but if that cost hits you hard, you should be asking yourself why you picked a high level language to begin with.Yes, in such a paradigm a place is needed where the entry point lives, but I found it fundamentally useful. Whatever you call the class it: - Can read and encapsulate access to env variables - It can accept commandline arguments (as main(argv[]) indicates) - It's the place to setup and configure your (object)- dependency tree (what IoC/Dependency Injection-Containers are doing) - Or it can be the ultimate exception handler for messages deeper in your program, e.g. where you would start your main message pump / game loop, etc.
The rest is ergonomics.
I am currently working on a Python/Django project of around 45k lines of code, 28k of which are tests. For me, this approach works quite well. It is not that I am against debugging or that I don't value debugging as a tool, but I just never feel the need to use one.
The tests also have a nice side-effect: because I do TDD a lot, I mostly end up with a lot of small understandable units, so I am effectively preventing code with properties that need me to follow each statement one by one.
I hardly ever feel the need to interrupt the running process to inspect the current variables. In many cases, this would be futile anyway, because I started writing a lot of generators.
def f():
x = 5
class Blub:
def incx(self):
nonlocal x
x += 1
def getx(self):
return x
return Blub()
j = f()
j.incx()
print(j.getx())
This will print 6, as expected.Although Java might be conceptually weak, empirically speaking it's a big winner, because developers appear to value ease of education, connectedness with others, availability of jobs and job security more than feeling stupid for not understanding lambda calculus. (that doesn't render formalist approaches invalid)
[1] https://docs.djangoproject.com/en/5.1/topics/i18n/translatio...