1. I write and rewrite more now. I view the first time the code works as just the first draft (like I would with a paper). Earlier in my career I thought that making it work meant I was done.
2. I spend a lot more time thinking about what's happening in the code and why. I have found some of my best work to happen after days of thinking about small bits of functionality.
3. I get the domain (ie. the big picture) much better. This is insanely valuable and helps me step back.
4. I listen more to opposing views. That's not to say I don't argue my point, but afterwards I spend time to rehash what the other person said when I have no pressure to respond. This guides my thinking a lot as it give me an opportunity to change views/positions.
5. I'm increasingly tolerant of other technologies. I use x, but y must be good too b/c smart people use it.
5.a While I'm more tolerant, I'm less distracted. When I was younger, I spent more time switching technologies to learn "new things". Now I spend more time going deeper on my current stack to learn new things.
6. I now think its ok to write code in a "non optimal" way if it makes it easier for the entire team to work with. I don't believe in writing to the LCD, however I do believe programming just a little above the team's moving average capability is probably better than writing above everyone's head (whether by me or someone better than me).
When you are 20 you are pretty much at the height of your mathematical abilities. This is fine for certain kinds of programming, but it is not really ideal for others. It ensures that algorithms primary and the domains in a real sense become secondary. As you get older, these tend to flip. You understand the domains better and may not be quite as good at generating optimal algorithms, but the tradeoff is generally positive.
Additionally I think there is a tradeoff that happens between dreaming of building great things and developing a craftsmenship approach to the small things. Engineer the small pieces well, and the big pieces will take care of themselves.
In most areas, I think one is better with a very mixed-age and mixed-experience team. Older, more experienced programmers bring something very special to the table, but the same is true for younger programmers as well.
This being said, I have a few very minor disagreements with you ;-). These may be split hairs though.
First, while I rewrite more in some ways, I actually find on the whole I rewrite less because I am not afraid to procrastinate while trying to understand the domain. People wonder why my code seems to come out fully formed and it is because I am not afraid to spend my time thinking about the problem instead of writing a rough draft.
What has changed is the sort of rewrites I do. I will typically re-engineer a small piece to remove cruft based on lessons learned from the last two years, rather than rewriting a big piece to meet a new requirement (because things tend to be designed more extensably now). So I am less afraid to rewrite and more willing to do so, but at the same time, I tend to rewrite less.
Finally there is the question of optimal way to program. I am of the opinion (probably in part because of how much work I do with Perl) that there is no singular optimal way. Optimal has to be globally defined and one of the jobs of the engineer is to ensure that the framework is optimal so that the team can program optimally. If the team is not part of the definition of what is optimal, then I do agree it is a mess.
But I don't think we are dealing with a single dimension here. Understanding the problems the team is struggling with is a good way to ensure that framework can be built in a way that drives that average capability up.
Is that really true?
There are many examples of people who came to mathematics late in life and did good things:
http://mathoverflow.net/questions/3591/mathematicians-who-we...
I think you only get better with time if you keep yourself sharp. What has changed for me is that I can't sit still and pound back Redbulls for six-hour coding sessions and then hit the gym. My process is also more methodical.
But mathematics is certainly one area I've only improved in with time.
Guess and check programming tends to optimize around fast reset cycles so that many, many solutions can each be tried with little investment. This is the programmer who loves to refresh their window every second to see how their changes impacted the product. It's high energy and exciting. It also lends itself to prepackaged solutions—be they existing frameworks of specific transliterations of known algorithms. I also find that it tends to generate spaghetti code more quickly (all styles do, but GnC does so more quickly) and to fall flat on tasks which have either slow reset cycles, long dependency chains, or are difficult to visualize.
"Slow" programming, for the lack of a better word, orients itself around a deep understanding of both the domain and the natural "seams" in the problem space. It involves a lot of quick drafts that are perhaps never even observed—the mere act of trying and failing to express the problem elegantly is highly informative. It tends to find less "obviously optimal" solutions because it's in search of novel optimal solutions. It also tends to be more easily guided by high-level goals such as business value or elegance. Finally, programming slowly requires great reasoning skills and thus is more amenable to tools and processes which enhance reasoning. It can take stabs at deep, difficult domains because it happily uses great domain modeling or mathematical skills to break those challenging domains into clever, interlocking, and simple pieces. For all this though it suffers from having a design aesthetic and becomes less willing to "just dive in there and try all 500 solutions" in case one of them works.
I think this cuts broadly across several stylistic differences in coders. I think that age and experience pushes one toward the latter style. I also think that they both have strengths and weaknesses—so I strongly agree that mixed style teams are valuable.
I would like to think I am, but recently I have noticed that everyone seems to want to jump on the NoSQL bandwagon. A lot of the jobs I see I would be a good fit want experience using MongoDB (or something similar).
I have been looking to learn them, but having read up on the technologies, I can't find a reasonable use case for any of them in my own work. One that would not be equally or better suited to Postgres or MySQL (which I know well).
I have come to the conclusion that 90% of people using NoSQL don't actually need it, and are throwing away a lot of useful features just so they can play with the latest fad.
That said, I think you're right that 90% of the time SQL is a better solution. You don't fully realize all the great stuff a real SQL engine does for you until you have to go without it.
I'm a pretty 'young' person, and a much younger programmer, so I can't quite say I got the 'oo shiny lemme use that' thing out of my system, but I'm okay with that (for now it doesn't negatively impact my work, and I learn tons of stuff). But in other areas of life, I've noticed that I generally become less dichotomous in my approach to new and other things, but more discerning too.
This is why i'd like to teach programming to kids. I really don't care if they continue with it or ever learn how to do anything useful, I just want to expose everyone to that feeling of power you can get when you're behind a keyboard and in front of the right tools. It makes you think you can do something amazing, and everyone should have a chance to feel that.
I'm definitely still an intermediate programmer, but I think I was always fine admitting that to myself. It was getting over the fear of others reading and modifying my code that took me a while.
I've found many bugs after I renamed variables like 'i', 'j', 'k', etc to something more meaningful. That made it easier to realized I was using them incorrectly.
This is basically why I think I'm an ok developer...
I pretend to be the smartest developer in my group (let's call him Bob). I look at a line of code and ask myself, why will Bob ask me the change this line of code? What will he prevent me from checking in? How would he solve this problem?
I do this even if I have a really difficult problem and Bob is the "go to" person. I pretend to be Bob and ask myself, What question will Bob ask me when I tell him about the problem? He will ask me if I've searched google, ok I will search first. He will ask me if I've checked for an upgrade to a library, I will do that. He will ask if I've set a break point here and checked for a memory corruption there. etc. 80% of the time, I find the problem myself and the rest of the time, Bob doesn't know the answer either. But at the end of the day co-workers are fooled into thinking that I'm as good as he is. But I have no doubt that Bob is better because it is important to him to learn everything he can about some key technology. I only approximate Bob when I need to interact with others. If you ask Bob a question, you get a quick and correct response. If you ask me, I will tell you I'm in the middle of something else and I will get back to you in a few minutes but really I have to figure out the answer first hahaha. I try my best to avoid getting help from Bob because, honestly, I don't think Bob respects people who aren't as passionate as he is (most people confuse passion with intelligence). The downside, is that it takes me a day to solve a problem that Bob can solve in a few minutes. Managers hate that but it is just too boring to learn technology to the degree that Bob knows it in my free time.
Another couple of ways to improve your coding...
Start with comments outlining what you're going to do. If you are pair programming, this shows the other person what your overall plan is. It also acts as a mini todo list. They should be "What comments". That is, what does this piece of code do, not how it should be done. Comments are better than just coding because you can do that quickly as a sketch to show your partner. Then they don't just sit there waiting for you to type out a lot of the algorithm.
You can also start doing this with tests first, which help you outline the interface for your object/method/function/module. This also helps you think about how easy your piece of code is to use by users of your code. ALotOf. ProgrammersDoNotThinkHowEasyYourFunctionIsToCall(x,a,3). Is it obvious what it does, and what the required arguments are for the caller? Is error handling sane for the caller?
Coding considering Revision control is very important, and these days acts like great documentation. With tools like git blame, you can see comments for pieces of code inside the revision control system. If you limit commits to nice small chunks on one topic at a time this is very helpful for people. Don't include white space fixes with 5 days of changes to 30 files at once, with a comment like "update". If they are nicely explained by the revision control comments, and perhaps even reference your issue tracker, then other people reviewing, reading, or bug fixing your code later will have a much easier time.
Finally, know when you are in prototype mode, pitch/demo mode, quick script mode, or Serious engineering mode. Each call for different approaches, and have different requirements. Don't let the Serious engineer get you to do a 10 day development cycle when you have a time limit of 1 day to deliver. That's a fail. Also, it's a fail if you hack something up without following all the development guidelines for some embedded life critical piece of software.
Having to explain to another what you're doing - I found that to be great as well. It removes bugs and produces cleaner code. You don't even need another - at check-in time, for every change, you can ask yourself "what is this doing" and "why". And if the answer isn't convincing, change what you're doing.
The value of peer-review was rarely on the peer's side - the other person doesn't really know what you're doing and is unlikely to catch a bug. But the peer would ask some question so you would start thinking about it and discover a problem.
The best thing about asking somebody for advice is often to come up with a good question. If you ask the right question, it contains the answer.
I see this a lot where the more experienced someone is the more they comment, but also where the comments are higher quality.
Something similar still serves me well as a general mental framework for approaching programming and debugging at a very local (procedure) level:
1. Make sure that the English language description of the algorithm is logically correct.
2. Make sure the code actually corresponds to the English description.
1. An english language description of what the function (or code block) does as a black box (forget the internals as they are subject to change). What you put in and what you get out, or section headings to structure how you read the code.
2. Comments in the code block to tell you why a given decision was made.
What this gives you is the framework you are describing but it further cements it into three layers:
1. Function and block documentation describe contract and what the code is expected to do from outside. If the code does not implement the contract the code is wrong.
2. When reading through the code as contract-implementation you can understand why certain decisions were made.
As bonus points, you get good API documentation.
Great code needs no comments.
Bad code needs lots of comments.
I've seen examples of both recently.
I randomly met a guy who told me of his idea to implement a UX framework with windows, buttons, views, etc in python.
A week later he sends me the finished framework. And it's perfect. It's easy to understand, all the names of things make sense, it's orthogonal. Not a single comment anywhere, but perfectly clear. Great code basically.
And there's a project I am maintaining where some parts of the code are pretty much impossible to understand, full of duplicated code - somebody loved copy&paste - duplicated method and class names, and threads going off in all directions. There is a comment for every line of code but despite the fact that I consider myself pretty good at reading other people's code, I am not touching that thing with a 10 foot pole.
My goal is to write code that doesn't require a lot of comments.
Great code implementing a particular algorithm for a particular reason might want a comment (1) identifying the algorithm and providing a reference to a published description, and (2) identifying the reason the algorithm was chosen.
Great code that is clear and readable and well-fit to purpose can still, very often, benefit from comments. Not everything that might want to be made clear to readers of code can be expressed in the code.
> Great code needs no comments.
The most valuable comments that code can't obviate are comments that explain why the code was written this way, the intent, and a summary of how the code fits into the overall picture -- maybe at least a file-level comment.I think declaring intent is the most valuable comment. What was the author going for with this function? Why is there a nil-guard here when the database column is `NOT NULL`? Is there an actual edge-case or is our data bad or was the author just being arbitrarily defensive against a boogeyman nil?
When reading other people's code, I've found that most of my time is spent figuring out not what the code does, but rather the author's goals and their higher level game plan.
I agree with other commentators that with comments one can at least express the intent and reasons for particular decisions.
And on a side note, it's wonderful to strive to write great code, but I believe it's easy to misjudge and think "Oh, I clearly write understandable code, thus I'll skip comments" even when it's not that clear. That certainly has happened to me, very likely to others at some point as well.
I can't be certain about your first example, but writing a UX framework is a pretty straightforward thing in terms of what it needs to do, so there probably wouldn't be much need to comment about what it's doing. Why, though - that's a whole 'nother question. Surely it's missing some of those whys.
The latter also forces you to keep a very clean code, and tricky parts (things you couldn't simplify nor make self explanatory) surface better.
Beginners are keen to get rid of all the legacy code. It's tightly coupled, it's hard to read, hard to maintain, yada yada yada. And then they tend to make a way too optimistic estimate on how long it will take. While it might look like nothing fancy from outside, under the hood it often handles loads of edge cases etc. Been there, almost done that (didn't fit in the budget which was way too optimistic already). Eh.
Experienced programmers understand that it's not perfect, but they just live with that. Surely there are some cases when maintaining the codebase would be waste of money because the previous coder was a disaster, and sooner or later it will have to be scrapped away. But it's more tempting to do that than actually needed.
On more than one occasion you would write a subroutine to do something, then a month or two later, you would see someone had already written that same functionality.
We once tried to contract this really fancy team to take over some code. They asked if we had unit tests. "No". "Then we can't do it, sorry, bye."
And I agree with them.
Even something as fundamental as version control is, I think, passed up by a lot of beginning/intermediate programmers because "it's complicated" and "I don't need it now because I'm the only one working on this." But a mentor can help push you into that earlier and walk you through some of the more common stuff in a more accessible, interactive way than an article or a forum, which goes a long way.
I ask this as someone somewhere between "beginner" and "intermediate". I've used git on a bunch of projects, but normally get hung up with branches or with trying to undo changes. Even harder than version control, I think, is getting a lone beginner programmer to write tests. When I'm writing something, it's always tricky figuring out exactly what it is I should be testing. When time is a limiting factor, it's hard to get from "I know I should be doing this" to actually doing this.
When you are good enough to make your own projects work the way you want them to work, but not good enough to contribute to the open source projects you actually use, how do you break out of your bad habits that you know you will need to break when part of a team/large project?
It wasn't something important to me for a long time since I did other stuff instead, but coming back to programming in an effort to make a career out of it, a lot of that stuff became instantly obvious & I felt foolish for not recognizing it in the first place.
I think one of the key things experienced programmers finally get is that we never stop understanding that there are things which we are doing sub-optimally and can continue to be reflective and self-critical of that. How can I structure my code better? How can I solve this software development problem that seems to come up frequently?
And then as we solve them, the solutions seem so obvious we wonder why we didn't realize it sooner.
Nowadays, it's the exact opposite!
I've mostly worked with higher level languages, and recently delved back into C. I had forgotten what a complete pain in the ass it is to pass complex data structures around between functions.
I'm a bit ashamed to admit my functions got pretty damn beefy real quick.
This is not entirely straightforward though - a bit of a rabbit hole you could say. e.g. should a programmer stop at the compiler? The CPU? The circuitry? Electronic components? The laws of nature? Tools are built with other tools after all and some tools are provided by nature...
On the other hand, if you haven't made even the first step towards understanding your tools then thats not really a problem to worry about.
Now, I wouldn't necessarily use PHP for this sort of work, but...
Those 100 line functions wouldn't make it through any half decent code review. Zero modularization, dal is inextricably linked to almost every piece of logic in the thing. Its an object called "Bitcoin" and I have a feeling it is 95% of mt gox' business logic if not all of it, it even writes raw xml to a temp pointer before dumping it into a cache and then making calls to header(). Separation of concerns? What are concerns?
Sure its tabbed neatly, and its got camelCasing, its using some form of orm/query thingy going on in there, but its still one hell of an unmaintainable, untestable mess.
I'd rather a thousand lines of spaghetti than ever having to work on something like that.
... Or may be I think like that only because I can see myself almost in every single line author posted :)
When I was still in high school I "invented" inheritance in PHP. I put one function per file, and used the include search path. When I discovered OO later I realized what I had done.
It happens :)
1. Read more books. Turn off Twitter, FB, whatever, and open your Kindle app. But be picky. Don't read crap.
2. Read every day. 30 minutes minimum at the same time every day.
3. Write code that implements what you learn.
4. Write code that is more consistent. Learn to write in patterns. Use patterns that you both learn from a.) books, b.) reading other people's code, and c.) that you come up with on your own.
5. Program by using coding standards. Either your own, or if you're in a company then follow the team's standards.
6. Review what you've written. Identify alternatives to the patterns you've used. How else can feature x be implemented? What do you like about each approach? What do the experts say about each approach. Then read everything you can about various approaches to a given problem and implement as many of them as you have time for.
7. Read some code written by someone way beyond your skill level in a language you know. Take in how well they write. Pick one thing they did well, read about it, understand it, then integrate it into your coding.
8. Rewrite something you wrote at least a year ago. Can you easily find a better way to implement this code? If yes, then rewrite. If not, then read more.
9. Learn one new tool that helps improve your workflow and get to a point of daily use.
10. Speed up. Use automation to eliminate the basic coding that you already know well and that is now wasting your time. Use whatever is easy for you whether its templates, macros, boilerplate, generators or automation. Just pick one and automate away the stuff you've already learned.
Repeat.
sitting down and learning a bunch of patterns and then using them without a deep understanding of why they are useful is misguided, and you'll end up with dogmatic code. not that it won't help, it's just not the most important step. the most important step is to write at least medium sized code bases without putting your ego into them so that you can be savvy to your mistakes.
The fact is that you won't get better unless you actually fail and are introspective enough both to realize you did (there are programmers out there who never realize this and I have tried, unsuccessfully, to work with them). So pick something you aren't sure you can succeed at.
The second thing is to be evaluating your development challenges as you go, be introspective, and learn from them. Every development challenge is an opportunity to get better.
The third thing to do is to start reading about cracking software and start working on cracking your own software. If you can get others to crack your software, better yet. You will learn a lot about best practices from this.
The fourth thing to do is to try to work with teams of open source developers and learn from others. I have never learned anything from someone who always agreed with me, and a friend of mine is fond of saying, if a village has two wise men who always agree on everything, the village has one more wise man than it needs.
Failure can be tough and sneaky: I didn't want to fail, so I Googled to see how others did it until I was sure... Then found I couldn't reach a consensus, and ended up "researching" for months. Sometimes doing it wrong isn't failing, after all, you've just found a way that didn't work-- that's progress.
Oh and reading or knowing how to do it isn't doing it. There can be quite a bit of work to doing it yourself, don't skip the exercises at the end of the metaphorical chapter ;-)
I've worked on enterprise software and people in the company thought of me as one of the better programmers there, but when I do open-source stuff I feel like an imbecile.
I quit my job and wanted to learn and get better, but I don't know how to start.
They will save you a lot of headache one day.
Really the only way to get better is to write stuff and ship it to someone who uses it, and you have to experience the pain of supporting it. That's when all the important lessons are learned.
--
"To me, the object-oriented approach was just a bunch of unnecessary overhead and boilerplate"
If you had made real C++, you would'nt have think of object oriented programming as an overhead. I suggest you to buy a few O'Reilly books (Probably the best code book )
I'm sure there are exceptions to this, but they are hard to find and universities aren't entirely to blame for it. Some parts of software engineering move fast and there is a justified fear to teach students things that will be useless by the time they graduate. So the focus is more on laying a solid ground-work.
http://webcache.googleusercontent.com/search?q=cache%3Awww.m...
I was amazed when I read that point. The only difference is that I couldn't get anything to build in Borland. I started out in BASIC making my motherboard beep to tunes in a BAT file.
"File under ego"
10 PRINT "COCKS"
20 GOTO 10