I've written a lot on this subject on SoftwareEngineering.SE in the past, and was in similar situations myself. Therefore, I'll attempt to give a few hints and highlight a few issues I noted when reading your question.
But first, let's talk about an important aspect: your role in the company.
Your role
You may have an explicit mandate from your boss to enhance things, and also a place in the hierarchy where other developers have to listen to your orders. Or you may be among peers, having the same role and the same authority, your option being only... well... an opinion.
In both cases, what matters is less your place in the hierarchy, and more:
What other developers think of you. If they treat you as an annoying guy who ask them stupid things, you won't get far. I've seen many cases where technical leaders and project managers had absolutely no influence on the team, because the team knew (or thought) that those “leaders” had no technical background required to take decisions they were taking. On the other hand, I've seen several developers who were actually listened by their peers, because they knew those developers are skillful and experienced.
How solid is your team and what motivates them. Imagine a company where every developer is paid for KLOC/month. Would anything you say about style matter to your colleagues? Probably not, because rare are persons who want to be paid less. In general, if this is not a team but just a group of persons working on the same project, you won't be able to improve anything.
Depending on that, you may decide whether it's worth the effort to make any change. If you have no voice and there is no team cohesion, just go look for another job. If you're known as a talented, respected developer and the there is a strong team feeling, you'll be able to improve things relatively easy, even if faced with the hostility from your boss or other teams.
In all cases, it is essential not to make pressure on your team. Work with them, not against them. Don't give them orders, but guide them towards the goal.
Now, the hints.
Style
I once asked nicely to follow the coding style and formatting of the majority of existing code (sadly we don't have a formal coding style document). But it didn't work...
Of course it didn't, since this is not the way it should be done.
Style is boring.
Following style is boring.
Writing coding style document is boring (and damn difficult; don't even try doing it unless you have worked with the language for more than ten years).
Reading style document is boring.
Reviewing code for style mistakes is boring.
Trolling that my style is better than yours is exciting, especially when there is absolutely no objective benefit of one style over another. Seriously, every sane person knows that the right way to write if (x)
is the way I wrote it, not if(x)
or if ( x )
!
Therefore:
Don't do style reviews. This is the job of style checkers. Those cute applications have a few benefits over your brain: they check the entire project in a matter of milliseconds, not hours or days, and they don't do mistakes and don't miss style errors.
Don't write your own style standard. You'll do it wrong anyway, and your coworkers will troll you that you made bad choices.
Don't force developers to fix 2 000 style errors.
Do enforce style automatically on commit. Code which has style mistakes has no place in version control.
Do it from the beginning of the project. Setting up style control in an existent project is difficult to impossible.
For more on that, read the first section of this other answer on SE.SE.
Also:
- Don't be too strict. For instance, writing
jslint
-compliant code is quite annoying, so it should be done exclusively when absolutely needed (or if all the members of your team are happy using it). The same goes for static checking tools; for instance, .NET's Code Analysis at maximum level could be very oppressive and depressing, while bringing little benefit; the same tool set at moderate level, on the other hand, proves to be very helpful.
Code reviews
Now that you don't need to bother about style during code reviews, you can focus on more interesting stuff: enhancing (vs. fixing) the source code.
Different persons react differently to code reviews. Some consider it an opportunity. Others hate it. Some listen to everything you tell them, take notes, and don't discuss, even if they could be right. Others try to argue on every point. It's up to you to find a way to deal with every developer according to her personality. It is usually helpful to:
Do code reviews in private, especially when the developer is junior and writes a really bad code.
Show that there is nothing personal: you are reviewing the code, not the person's skills.
Show the actual goal of a code review. The goal is not to show how bad a developer is. The goal is to provide opportunities for improvement.
Never argue. You're not here to convince, but to provide your expertise.
Never assume the reviewee is the only one who can learn something from a review. You're here to learn too, both by reading the code and by asking explanation about the parts you don't understand.
Once the code review is done, make sure the person actually improves her code. I had a few cases where developers thought that code review ends when the actual meeting ends. They leave and go back to their new features, trying to apply what you shared with them for new code only. Having a decent tracking tool for code review helps.
Note that independently of your particular role in the company and your expertise compared to others, your code should be subject to review as well. You shouldn't be the only one reviewing others' code either.
In a recent project where I worked as a technical leader, I had a hard time explaining to my coworkers that it's their role to do the reviews of each other's code, including mine. The fear of an intern who is about to review the code of his technical leader disappears as soon as he finds the first issues in the code—and who among us writes flawless code?
Training
Code reviews are a great opportunity to teach and learn some of the aspects of programming and software design, but others require training.
If you are able to train your coworkers, do that. If your management is hostile at the idea of training, do it informally. I've done such training sessions in a form of informal meetings, or sometimes even as a simple discussions, sometimes interrupted by management and pursued later.
Aside direct training, make sure you know well enough the books such as McConnel's Code Complete, and talk about those books to your coworkers. Suggest them to read source code of open source projects, give them specific examples of high quality code. And, obviously, write high quality code yourself.
Focus on context, not on persons
How can I address this situation without just focusing on 'bad company culture', 'inexperienced graduates', etc.
Those graduates have a goal: acquire experience, learn stuff, become more skillful. If, year after year, they write crappy code and know nothing about programming, it's probably because your team or your company is not giving them this opportunity.
If you're focusing on the fact that your team has inexperienced graduates, this won't help. Instead, focus on what you can do for them and with them. Code reviews and training are two of the techniques to improve the situation.
Bad company culture is a different beast. Sometimes, it can be changed. Sometimes, it cannot. In all cases, remember that you are part of this company, so you are part of the company culture. If you can't change it and find it inherently bad, sooner or later, you'll have to leave.
Get your metrics right
How exactly do you measure code right now? Do you measure the number of commits per day per developer? Or the KLOC per month per programmer? Or maybe the code coverage? Or the number of bugs found and fixed? Or the number of potential bugs caught by regression tests? Or the number of reverts done by Continuous Deployment server?
Things you measure matter, because team members are adapting their work to the factors which are measured. For instance, in one company where I had to work a few years ago, the only thing which was measured was the time one spends in the office. Needless to say that this wasn't encouraging to deliver better code, or to work smarter, or... well, to work at all.
Figuring out positive and negative reinforcement and adjusting the measured factors over time is essentially the leverage you have on team members. When done properly, it makes it possible to achieve results which won't be achieved by simple hierarchy.
The things which bother you, make them measurable. Measure them, and make the results public. Then work together with other team members to improve the results.
For example, let's consider that team members make too many spelling mistakes in the names of classes, class members and variables. This is annoying. How could you measure that? With a parser, you can extract all the words from the code, and using a spell checker, determine the ratio of words containing mistakes and typos, say 16.7%.
Your next step is to agree with your team on the target ratio. It could be 15% for the next sprint, 10% for the next one, 5% in six weeks, and 0% in two months. Those metrics are recomputed automatically on every commit, and displayed on a big screen in the office.
If you don't achieve the target ratio, your team may decide to spend some more time fixing spelling mistakes. Or your team may consider it better to compute the ratio per developer, and display this information on the big screen as well. Or your team may find that the goal was too optimistic, and that you should review it.
If you achieve the target ratio, the next step is to make sure the number of mistakes and typos won't increase over time. For that, you can create an additional task in your build which checks for spelling mistakes, and fails the build if at least one mistake is found. Now that you got rid of this problem, your big screen may be reused to show the new relevant statistics.
Conclusion
I believe that every aspect mentioned in your question can be solved through the techniques I included in my answer:
When other developers joined the project, I noticed that they use a different coding style (sometimes a completely different style)
You had to enforce style automatically on commit.
and often don't use modern language features like property accessors (this is relatively new in Objective-C).
Both code reviews and training are here to transfer your knowledge of the language.
Sometimes they would invent their own bicycles instead of using similar features of the framework
Both code reviews and training are here to transfer your knowledge of the framework.
or transfer concepts from other programming languages or patters they learned into our code base.
This is an excellent thing. Seems like an opportunity for you to learn from them.
Oftentimes they can't name methods or variables properly because of bad English
Code reviews should also focus on proper naming. Some IDEs have spell checkers too.
Sometimes I think if it wasn't for the IDE I think they would write all code with no indentation or formatting at all.
Of course they would. Style is boring and should be automated.
Basically, I hate the code they write.
Remember from the code reviews part: “The goal is not to show how bad a developer is. The goal is to provide opportunities for improvement.”
It's badly formatted/organized, and sometimes is radically different from the rest of the project.
Automated style checking.
I feel very upset when they add their spaghetti to my piece of art
Wait, what?! Piece of art?! Guess what? Some persons (including you in six months) may find your code far from being a piece of art. Meanwhile, do understand that considering your work as a piece of art and their work as crap won't help anyone. Including you.
It feels more and more like they can't be bothered to learn or don't care: they just do what's required from them and go home.
Of course they will do what's required from them. Remember: context, not persons and get your metrics right. If the context requires from them to become best at what they do, they will do it. If the context requires to produce as many KLOC per month as possible and nothing more, they'll do it too.