This is really kind of the whole idea behind the "red, green, refactor" mantra. The point isn't to write perfect code right out of the gate, it's to write working code. Once the test is green, then you can refactor as necessary with the confidence that you aren't going to accidentally break things (as the test will backstop you).
Ironically, I think this is something that affects seasoned programmers more than new ones; the more you know about the trade, the more voices you have saying "no, that's wrong! Don't do that!", which can freeze progress. The way I combat it is by writing down pseudocode in my source code - literally just english, non-compiling pseudocode - which I then "refactor" into working code (thus the first "green" is "it parses"). By making step 0 the expression of the idea rather "writing the fist line of code", I can get right into the process rather than getting hung up on the "how".
Also kind of related - programming by "wishful thinking". You first lay out the flow of the program as calls to high level functions which don't yet exist, and then go back and fill in the functions as you can. The first few SICP video lectures are all about this style, and I found the idea simple but very useful to avoid trying to hold too much of a problem in your head at once.
Yes, exactly. By writing pseudocode, I end up writing business code rather than implementation code, which inherently assumes the a high-level interface to the nitty-gritty details. This leads to an approach where the idea is expressed at a high level first, rather than getting stuck in the implementation details of some small piece of the problem.
It's kind of "breadth-first search" on software development, while the classic approach is more "depth-first search".
On the other hand, it is also important to quickly get into the state of a running program, because only that allows for iterative development where you can catch bugs shortly after you wrote them, rather than having tons of bugs after weeks of (not sufficiently tested) work.
I've always heard it as top down development, as opposed to bottom up development. I always say that's what I'm going to do, and then end up not doing it.
I've found what I think is the SICP book, but I can't track down the video lectures - can you provide some links? Thanks - I thought I was the only one programming by "wishful thinking"!
Sometimes I'm surprised at the lack of parallels between writing long-form articles and writing code. How many people draw a general outline of their program, what they want each part to do, and how the whole thing should be layed out? Who plans before they start coding it?
Code is a planning language, so rather than boxes and noodles or pseudocode, I tend to sketch out my plans in code itself. In SICP this is called "design by wishful thinking": you pretend that you already have a library of primitives that do the nitty-gritty work and write the high-level bits of your program using those primitives. Then, you go back and implement the primitives.
Indeed, the "design by wishful thinking" was a real eye opener for me. It is one of my favourite parts of SICP.
It can also be explained as way to postpone decisions you can't clearly make right now. First, you pretend to have made the decision, and later on you implement the decision "you wish you had made".
Definitely an effective technique. Personally I like doing this on a whiteboard so I don't get distracted by errors or Compiler/IDE notifications and can just sketch mostly in realistic looking code.
For smaller segments though, I'll just write out function signatures, an then go back and fill em out or restructure them.
I think these types used to be derogatorily referred to as "cowboy coders" in the 90's by overly process oriented developers who came from an era of mainframes and punchcards.
I think a big shift in modern software development came about when people finally realized that developing software is by nature a "messy" process. Loose text files, REPL sessions filled with red lines on the console, randomly scribbled boxes with arrows on loose sheets of paper strewn about the room; traversing object graphs in your head while on the drive to work. There is no "outline" to frame any of that. The outline only exists after the software has been built.
Yup; which is why the people getting hired for those projects would flounder if asked to make a large individual contribution without much handholding; and also why those types of project team structures yield such incomprehensibly shitty software (at ridiculous cost to the client.)
Seriously? Many of the enterprise devs I know do make large individual contributions in their own (side) projects, or in smaller projects within the organization. Part of enterprise dev is that you are developing within a series of constraints, not least the thought in mind that there is likely to be someone maintaining this code in 10 years time, and it's unlikely to be the team building it today.
I would agree about the general outcome, though - enterprise software often is built _despite_ the politics between various departments and vendors, and much of the solution is as a result of compromise and integrating with "not quite suitable for current purpose" legacy systems. That is where a large amount of the cost goes. (It's also important to remember that what we're building today is also going to become the legacy system of tomorrow, and to include that thought in the design).
Maybe I've been spoiled by working with embedded C++ on Arduinos, where we have 3 sections -- Initialization, Setup function, and Loop function. We set variables and include libraries in the Initialization section at top. We run first-time code and open serial & other connections in Setup. Most code goes into the Loop section, which is the function that does the heavy lifting. Extra functions (i.e. the math to convert inches to mm) can be written below, and called in either Setup or Loop.
This is why programming language history is so important. Every programming language has a large number of opinions/assumptions. Code structure is one of them. The Arduino language, based on C/C++, has assumed a simple code structure that helps people learning embedded programming, because the Arduino platform was designed to help people learn.
developing software is not messy process. what is disturbing is that you think it is and that is normal state. Sure it is messy if you develop by accident so lets see what sticks.
Recently (as in a crazy experience over the past week), I've been feeling the same way described by you, and by the OP; but I've scaled this up to a much higher abstracted level.
The only way I can really describe it is (in terms of what you just said): "red, green, refactor" your life, not just your job. Constantly question everything you're doing, and find out what you don't like about it. Find the root cause of that feeling, and figure out what you can do to fix it. Find and take the steps to complete that.
Edit: I will add though, that the trick is to do so without stopping progress, as you said.
I really like your common English approach to coding. As a designer I often do the same with a few key points that my client and I have discussed with some additional influences taped up around my desk.
Using a visual git client greatly helps with this approach, especially if you are coding in multiple files at once. Once you have "green" status, look over the changed lines in the git GUI and look for lack of patterns, code smells, etc. This separates the coder in you from the reviewer in you.
Perhaps I'm misunderstand you, but what difference do you see for this use case between visual and command-line git clients? I do this all the time with git-diff on the command line, and it might just be a failure of my imagination, but I can't think of how the process would be any different with a visual client. Can you give an example?
Different strokes. I'm like you: I do a git status from the CLI for peace of mind. Others in my company gotta have their SourceTree, and hate the CLI. I disagree, but it's their choice.
I program the way that I imagine I would sculpt. If I had to sculpt a head, I wouldn't start by sculpting the perfect ear, and then sculpting the perfect eye, etc, because who knows what will happen. Maybe in the course of sculpting the eye, I need to move the ear, and then all that work goes out of the door.
Instead, I would sculpt the entire piece of art roughly, almost unrecognizably, and then target large parts of the sculpture. Details like ears and eyes might even never get done, depending on how the requirements change for the sculpture.
I always approach writing software the same way, so the first iteration is just a hardcoded piece of software that just shows me that it will actually work, and then I iterate and start smoothing out all of the sharp edges, of which there are a ton.
People interpret "just do it" as practical advice to write good code, but really it's practical advice to get code from people who won't otherwise write anything. Good code comes from both will and knowledge. When you don't have knowledge, will alone will do.
"Just do it" is the best advice for stuck people - you tell them to just start doing the thing, not worry about details, and eventually you'll do it right. This is good advice for a business guy who's pin-wheeling ideas in his head, a programmer with no product sense, or anyone else who wants but does not make.
When you know a little bit about what you want to build, and maybe even a bit about _how_ to build it - when you have some actual experience, skill, and will - then the right advice is typically to slow down and think it through.
What keeps me from coding is not necessarily optimization (well, at least its connotation connected to speed), but maintainability...By that I mean the constant battle between, "Do I write the boilerplate I need to set this up right?" and "Let me just copy/paste/mock all of that". To me, this is a more sapping concern than optimized code, because taking too many shortcuts makes the project harder to maintain in its midstages...even worse, the shortcuts can cause sloppiness to cascade into the design of all the other dependent objects and interfaces.
Doing some nominal TDD has helped quite a bit for me, because it does require writing code, but not code that I have to worry too much about (and if it happens to be a pretty shitty, shortsighted test, I can delete it without it, theoretically, hampering the app) screwing me over. Sometimes this physical act is enough to get me past the code-writing block.
Also, if I actually do the testing right, it prevents regression, improves code quality, etc. etc.
I think it ultimately comes down to "choose the right tool for the job". TDD is just one tool that you have in your toolbox to accomplish whatever project you are working on. That doesn't mean that TDD is appropriate for every project.
The mistake most people make is that they mix learning and doing in a single round. It's much better to write a prototype with a specific goal of wringing as much knowledge from it as you can without being distracted by scalability or maintainability minutiae. Then, and only then, will you be ready to write The Real Thing with all of the bells and whistles. In the end you'll probably save more time than if you kept going back and forth waterfall-style between learning and doing on the same codebase. You'll certainly end up with a better result.
P.S. That quote is from 1975. To quote another great mind (Santayana): those who do not know...
I remember when Facebook's front page code leaked. I am no PHP expert, but it was pretty ugly code. Probably today you couldn't get hired at Facebook if you wrote code like that.
I've heard many arguments where people will tell you, it won't scale. Or you're doing it all wrong by writing quick and dirty procedural code. Quite frankly scaling is about the nicest problem to have if you're a startup. Without traction your ugly code simply isn't going to matter. With traction you will gain funding and the ugly code problem quickly disappears like I assume it did at Facebook.
> Quite frankly scaling is about the nicest problem to have if you're a startup.
I'm certain I stole it from someone here on HN years ago (whoever it was, I owe you a beer!), but I've always called this a "Maserati Problem". That is, it's something I can think about while I'm driving down the road in my Maserati that I've purchased with money my startup has made already.
Scaling, in most cases, is a problem very much like "where am I going to store all this money that's pouring in?!" If you have it, you've already won.
Hindsight is always 20/20. It's difficult to judge a piece of code after the fact. The quality of the code, including maintainability, is a result of various trade-offs. We don't know what compromises the developer was making at the time. We don't know what was the highest priority at the time. May be they were short of money and working code however shitty produced at the shortest amount of time was the most important. Suck to be the guy doing the maintenance but if there's no working product, there would be no maintenance.
We programmers have a ugly tendency to judge less than stellar codes written by others. It made us feel superior to pick apart mistakes others have made. The fact is software development is a series of technical and non-technical trade-offs. I certainly had fell in the same trap before. These days I just appreciate they can ship a working product and get it off the ground.
I'm by no means a pure functional programmer, but I've found some of the mantra from that paradigm helps when building the early blocks of a program as it allows you to break down your application into core problems which can be tackled individually. Plus it allows your application to scale easier and makes it easier to rip out and replace code as you start to add complexity.
But of course, before starting any major project, the first thing any developer should do is map out at least a basic mental design of the program - even if that map isn't written in pseudo-code or in a form of a flow chart.
The reason pure functional programming is good for "ripping out and replacing" code is because your code units necessarily have fewer interdependencies.
a pure functional language is really good for writing dumb code that "just works" in the sense that it does what you need it to do even if it isn't very pretty or fast, while at the same time keeping it reasonably maintainable because the code will not be rife with accidental complexity and assumptions about global state.
in other words, FP evolved to solve hard problems. You don't need to understand monads to model a cash register. You probably do need monads if you want to write a bug free distributed asynchronous system.
I don't know that you need monads, but a lot of recent languages seem designed to guide programmers to certain types of good design. You don't need the language to emulate the design ideas.
Be careful going overboard with pure functional programming. It could become one of the immobilizing factors the blog was talking about. Is the code pure FP? Can I get rid of the states? Am I doing correct FP? Should I write generic function for more abstraction? Am I doing DRY enough?
Indeed. It's about knowing what tools are best to use when. My comment was more about how some (albeit not all) of the concepts of functional programming can help tackle the first few stages of larger projects and can often help to lower the chances of spaghetti code.
I've missed coding with whimsy and curiosity. There was a time in my life when it wasn't all engineering. Characters from the Lord of the Rings trilogy made their way into tutorials and references to the Flying Circus were everywhere. Communities were a lot more accepting of newcomers and few people were so paranoid of bad, unmaintainable, spaghetti code. There was less of a focus on being a 10x developer and more on learning, having fun, and doing neat things.
I'm probably remembering things with rose-tinted glasses.
These days, even in open source -- the once proud land of eccentric hackers and the can-do spirit, there is such a negative focus on bad developers. I can certainly see how the OP could feel paralyzed when just trying to write a line of code.
In reality we're all at different points in our journey and have had different experiences along the way. There's always room to improve ourselves and it's important to listen to criticism so that we know where to start. But sometimes you just need to cut loose and let it all hang out. I started writing a library I call "Horton," for this very purpose: whimsy, pleasure, and most of all to avoid the engineer mindset!
In order gain insights and develop new ideas you have to find new hunches and investigate them. It's hard to develop hunches in a vacuum where your reality doesn't expand beyond your own self-made bubble. You've got to push once in a while... and people out there who complain so loudly about shitty developers? Get a life and help someone out. We're just making programs.
I don't know--my impression is that most people go to far in the other direction. They write code with no thought at all for the future, and then shortly have nightmarish debugging sessions in spaghetti code that's impossible to extend or reuse. All in the name of a rather extreme "worse is better" philosophy.
I've certainly experienced this with some of the people I worked with recently. Anything you win in the short term gets lost several weeks--if not days--later when everything is a horrible mess. Don't even think about coming back to that code months later!
I've found that putting in a little bit of care for the future pays off even in the short term. Perhaps not on the scale of hours or days, but definitely weeks. Which is still pretty immediate.
However, how you do this is also very important. The handy rule I've been using is simple: simplicity. Improve your code by making it do less not more. If you can make code more maitainable or general by simplifying, do it. If it would require adding new concepts or mental overhead, reconsider. Try to reuse existing abstractions as much as possible.
This usually--but not always--means making your code more functional. Do you really need to write this operation in place? Do you really need to tie everything together with a bunch of implicit state changes? Probably not! This is not to say that you should never use state: just be sure to only use it when it fits well and makes sense. And be explicit about it.
The functional style (at least in languages like Haskell) also lends itself very well to reusing simple and general abstractions. The key idea here is that these abstractions are not about doing more: they're about doing less. More general code simply leaves you less room to make mistakes. If you're working with lists of numbers, there are all sorts of arithmetic mistakes you can make; if you manage to write the same code against lists of anything, the only mistakes possible will be in list handling.
Haskell just makes this more practical by providing abstractions with a great "power-to-weight ratio": ones that manage to be simple, general and yet still expressive. Code with functors or monoids or traversables is easier to write than more concrete code and yet still flexible enough for many useful tasks. As a bonus, it's also more reusable. For free.
So the key idea is reduction: all these abstractions work by stripping concrete types of power. A functor can do much less than a list. A monoid can do much less than a number. This lets you write nicer code without becoming an "architecture astronaut" because instead of adding structure, you're really taking it away.
I've found that programming like this really helps in maintaining and extending the code later on. But it doesn't slow me down when I'm writing either--I actually save time because I spend less getting time getting the code correct in the first place.
These days, I've started being able to make large changes or add complicated features and have them work on the first try. Not every time, but surprisingly often. Certainly much more often than before! In large part, I think this is because of writing the code with an eye towards simplicity.
So the important insight: take the simple route, not the easy route.
How long have you been programming, and how many jobs have you had writing code in an actual business? Your profile says you're a student, so I'm curious how you can feel justified in writing such a thesis.
Personally, after 16 years in the industry, I do stress about my code as described in the article... Not about making it work, because that will happen regardless, but about how. It affects my ability to code, because "make it work" is far drowned out by "make it work the way your peers will accept it." Many times, that "acceptable" approach is something I find far less intuitive, and far less maintainable... Also, that approach has changed so many times over the years and with each different team, it's hard to keep track. I can build far more in a weekend, on my own terms, than I can build in a week by someone else's. I am not complaining... I actually like to learn those terms, and I enjoy it as long as people are constructive about it rather than condescending. It's trying to pre-determine those terms that is the block, for me.
wow, SO experience is now something one puts on top of the Achievements section! (I don't say it in a bad way, I'm just surprised things have evolved to such a point)
If you write code too slowly, go faster. If you write code too quickly, go slower.
You can tell if you're too slow when you've spent two weeks thinking about the program and have neither working code nor a detailed design, or if you've created a detailed design only to realize upon implementation you'd gone about it entirely the wrong way.
You can tell if you're too fast if you find yourself spending more time cleaning up messes of poorly-thought-out spaghetti code.
This is like in go. If your walls are too brittle, play more conservatively. If your walls are too thick, loosen up. You can make generally better moves in go just by recognizing if you are too conservative or too aggressive. Same with poker.
Sometimes you'll want to plan ahead because the nature of the problem means you'll have a harder time cleaning things up later.
Other times, you want to move quickly because creating castle-in-the-sky architectures is not the best use of your time (especially if it becomes paralyzing).
Experience helps you determine which type of situation you're dealing with.
The problem that comes up is by the time you hit the tipping point of more cleaning then feature additions you end up having to do the fast solutions to fit deadlines.
I think when you take on the debt of poor code you have to remember that what it will take to fix that problem will continue to increase the longer you are away from that code.
Now I don't think you should consider fixing things for scale poor code that is it's own beast which makes the most sense to handle once you have the problem as you can't really tell what the problem will be until you have it.
You're going to see a lot more code from people who err on the side of too little thought rather than too much though for a pretty obvious reason: people who are too scared to start coding... aren't writing any code for you to read later.
Also, while it's easy to identify code which has had too little thought put into it, it's often very difficult to identify code which has had too much thought put into it. The best solutions don't look like the result of lots of hard work, but rather make hard problems look like simple problems that would be trivial to solve.
Great advice IMHO. One trick that I found useful for myself (good chunk of my code is "hobby" code that I myself revisit some months later, so not really "production" problem but nonetheless almost the real-world maintenance example):
- make the function fit in your head. Literally. Make it fit in one screen, if you can. If it does not, think how you can make it fit on the screen - everything, including variable definitions.
- avoid branching as much as possible unless it is the 'exit' branches. Avoiding branching sometimes can be done by tricks like passing function pointers. Do it - it makes code much more expressive and easier to read.
These two heuristics allow me to make the code much simpler to understand for $(me+6months). I saw the same patterns in real-world code at $work as well - using the above two principles makes the code dramatically easier to support later.
One screen is way too big! Make each function do a single thing. Even in verbose languages, you should be able to get most of them down to 5 lines or less - and this isn't actually difficult (except for coming up with names for all of them) the transformation is actually very mechanical, so much so that if you're using an IDE it can probably "extract method" for you, but even doing it by hand is trivial once you get the knack of it.
Indeed. 25 is the maximum - mostly the shorter, the better.
Though at least for me there is somewhere a limit (2-3 lines?) where the returns start to diminish - there's more noticeably more typing involved, and more mental context switching while debugging.
> Improve your code by making it do less not more.
Exactly. The problem is that code can tend to be either crap (spaghetti) or too much code (too many methods and layers of extraction). So, I'd go one step further: code should do less, not more, and should be clear and understandable, without making unnecessary sacrifices. What is clear to me isn't clear to everyone else, but striving for clarity and simplicity isn't a bad thing.
After writing tons of code, I've come to realize that 80% of the time, it takes about the same time to do it "right" (scalable/secure/modular) as it does to do it "OK".
Ex: Are plaintext passwords any faster to build/code than encrypted+salt passwords? Nope.
And, it's fine to intend to refactor later. But, too many organizations have no tolerance later to let engineers do things that don't have visible results. I've suffered through a stint of handling "legacy code" like that & it was painful & demoralizing.
In general writing a trick to get around this is to do a 'vomit draft' -- intentionally write something bad.
In part, this is simply to get past the analysis paralysis or creative block and get going on something. But also because it can sometimes be easier to make something good when you have a clear bad example in front of you to contrast it with.
Occasionally, I find myself “stuck” when writing code – the coder’s “writer’s block” I guess. This quote by Ward Cunningham is both inspiring and truthful:
-- Once we had written it, we could look at it. And we’d say, “Oh yeah, now we know what’s going on,” because the mere act of writing it organized our thoughts. Maybe it worked. Maybe it didn’t. Maybe we had to code some more. But we had been blocked from making progress, and now we weren’t. We had been thinking about too much at once, trying to achieve too complicated a goal, trying to code it too well. Maybe we had been trying to impress our friends with our knowledge of computer science, whatever. But we decided to try whatever is most simple: to write an if statement, return a constant, use a linear search. We would just write it and see it work. We knew that once it worked, we’d be in a better position to think of what we really wanted. --
Next time you’re stuck, just write the simplest thing that could possibly work!
-- So when I asked, “What’s the simplest thing that could possibly work,” I wasn’t even sure. I wasn’t asking, “What do you know would work?” I was asking, “What’s possible? What is the simplest thing we could say in code, so that we’ll be talking about something that’s on the screen, instead of something that’s ill-formed in our mind.” I was saying, “Once we get something on the screen, we can look at it. If it needs to be more we can make it more. Our problem is we’ve got nothing.” --
I write news articles in addition to code, and a fellow writer gave me a simple piece of advice that I think applies to both disciplines. It has to do with planning -- but not over-thinking -- your work.
Before you start writing, sit down with a friend in a bar and explain to him exactly what you're trying to say and do. If you can't communicate your idea in a concise, conversational way, then you're not ready to start writing.
you need to learn calculus if you want to model relativity. you only need fifth grade math to model a cash register.
if your team builds apps with 500k LOC, you need to be constantly focused on abstracting and factoring out patterns or you will drown in your defect rate before the project even ships. If your team builds medical device software, if you aren't doing this, you'll get someone killed.
If you're building a personal blog, your time is better spent by pasting jquery snippets.
There is a spectrum here and most projects fall somewhere in between.
Of course. And to add an example of the other part of spectrum (opposed to medical device software) - bunch of simple 2d game prototypes. There's people who do such jobs, and many similar, who'd be a fool not just "push the buttons" all the time, with basically just a quick forethought related to structurization and code quality.
I can identify with this. Some of the best work I've ever done has been some of the worst code, just because of the paradigm shift involved: "get shit done" instead of "write nice code".
"And all that is fantastically interesting, but completely beside the point. I just fell into the classic programmer trap of exploring and learning about (what I find) fantastically interesting things that will address all sorts of amazingly complex situations, but which the learning of said things resulted in absolutely nothing of tangible value being created."
I disagree. Too simplistic. It's my job as a developer to try and think of all the ways my project can fail and bog down before hand (within reason on the performance). I've got a list of items I am actually working on and will post it above my desk when done:
1. Let me think about this some more before giving you an answer.
2. I will use my debugger.
3. I will create a new branch for this task.
4. I have commented my code and commented it well.
5. I have accounted for fail scenarios.
6. I have considered multiple solutions to this task.
7. I have not begun hacking away immediately at a task.
2. Refactor when necessary (either because you got to a dead end and can't keep writing code fast anymore, or because you're done and want to move on to another task).
The problem with this approach, while great for you, the developer it is a nightmare for the future team.
I am now working at a startup where the early devs have left. They did precisely what was needed at that point - build quickly, ensure it works for the 3/4 customers we had back then and document it as well.
Fast forward a year later, that same code is no longer extensible for many clients. Its rigid and tightly coupled and rewriting some parts means, we have to pretty much rewrite a whole lot more than we bargained for. We will have to burn through a lot of cash to just build a whole new product based on some of the scalability and maintenance learning we now have from a year of learning and growing to client# 100.
The point is, there is always going to be "this is the right thing right now, its what our customers want" and then something else for the future.
I have seen that people who have worked for a while and in many startups do the smart thing (as expected) and while follow "build for now" they also do the sensible thing of investing for the future (from experience).
I can relate to this. There is a real risk in freezing up when you attempt for your first writing of code to be the fully architected solution.
I would still go one step further and at least apply the strategy pattern/polymorphism when you have a large if/else/case block going beyond 2 or 3 conditions in a controller or model or something. (assuming MVC web apps)
The fact is you can write out some ugly code directly in a controller where it might get some code working fast and prevent the freeze up of your output, but once working you should immediately move it to the appropriate place like a model or library, and apply a basic OO strategy pattern (perhaps not with factory/interfaces etc until needed later) where appropriate to cut down on spaghetti/nested conditionals.
This really does not take much more time than stopping at working code that is ugly, and is a good middle ground where it is not painful to return to later.
There is still no good excuse for "taking a dump in the corner" of your code base just to get a marginal gain in output.
I can relate to this, somewhat. I've spent quite a bit of the last few years writing code either under deadline, or for work that's ultimately charged hourly. That doesn't lend itself to thoughtful refactoring.
As such, when I'm not under those constraints, I sometimes go a little overboard factoring out duplicated code and looking for the beautiful solution. To me, beauty is the maximization of clarity and conciseness. Since I'm usually writing Perl, there's quite a lot to work with in that regard.
For example, yesterday I spent 4-6 hours writing approximately 40 lines of Perl (along with another 40 lines of tests).
On the plus side, what I generate during these binges is generally an efficiency multiplier for the other code I write, as well as a god way to really examine some of the more esoteric, but useful, ways to use your chosen language.
This is a great post. I just wrote about a project I worked on in February[1]. When I first built the website, it wasn't optimized and now I realize that I greatly over estimated how many resources I thought the site would need.
Last week, after getting to the first page on Google's search results, I'm getting about 12,000 hits a week. Monitoring shows my daily CPU usage is nearly 0%, and memory usage around 32MB. Today(3 months later) I finally did some SEO, added compression, caching, and a CDN to get drop page load time from ~2 seconds to under 500ms.
"Build it, release it, analyse it and only then decide if it needs optimising." I think it depends from company culture.
The thing is if you don't do it right with first go you will have hard time to get it done later. What management cares if it works, it's your responsibility to make it right from the start and they probably won't give you time to make some refactoring/optimizations later, because time is money :(. Sometimes it's hard to explain consequences. I have seen this too many times.
I believe you need to find golden middle, by not trying to hack things to much or overengineering problem, though sometimes is hard to define where is this middle.
"We are what we do repeatedly." If you spend time thinking about best practices, it becomes easier and less time consuming. You need a balance of it early in your career but if you're constantly working at it, it'll become second nature. In my opinion, the best programmers are the ones who have exceptional practical wisdom, who know when to utilize a rule and when to yield to exceptions (no one likes a ferengi programmer -- http://www.codinghorror.com/blog/2009/02/the-ferengi-program...).
Build it, release it, analyse it and only then decide if it needs optimising.
I often share a similar sentiment with teams I work with: Don't throw solutions at undefined problems.
That commonly applies to performance and premature optimization.
I'll agree that there needs to be some thought as to what's being built before, and while, doing so, but spending time resolving as-of-yet-undefined problems means decision making based on high levels of uncertainty.
Get something working and let problems define themselves. Often times, they do so in a way that makes them easier to fix vs. relying on the speculative solution making I mentioned above.
There are thousands of guidelines and many of the contradict each other .. there are many advisors creating posts, tutorials, patterns but I think you should work the way your ecosystems require it , don't try to be perfect just get things done and ensure your code will work in critical cases.
Sometimes I wish I could be up to date in all the best practices but is just impossible some developers like me we work with deadlines and there's not much chance to try new things.
One thing I've learned from having to do rapid prototype development is to just put fingers to keyboard and go.
If I find myself getting stuck in the cycle of "this can be written better, I'll just spend 2 hours improving it rather than finishing the framework" I stop, I think about it, then I leave the working-but-probably-crap code in place and move on.
Once the framework is in place, then I start making things better, one area at a time.
Thinking about scalability or portability of the code from day 1 is useful because it may be difficult to crowbar those things in on day 200.
That said, don't dither too much over writing code. History favours the doers rather than the vacillators. Most software except for utilities has a quite short working life anyway. There is also the standard advice of "expect to throw one away".
Actually you need to stop earlier, I've found that quite a bit of the stuff that people think they need to have built isn't even close to needed in reality. In fact, building it and shipping it can be a major mistake itself.
So I completely agree on the underlying principle: Dont to _anything_ prematurely, and that first and foremost includes actually writing any code at all.
This point is very like an engineer's point, which have many years of development experience. He tell me when I'm a intern in the company. I always like to write perfect and complete code that time. But you must write code first, so that other people could cooperation with you. Just write and see and test, then you can find the problem.
This is the god-knows-which time this link surfaces on HN and I keep saying the same thing - once all this stuff is ingrained you don't think about design patterns, you just do them. Either that or you decide what to do in a design session or on the whiteboard.
Thinking about this stuff is the sign of either a newbie or lacking up-front design.
There's a freaking huge difference between double checking every single line of code, and coding a new features (hundred, thousand of lines of code) with a scalable design.
Does that resonate enough for you?
Seriously, seeing stuff black&white is how bad code happens. (And so many other things in life.)
There's another approach from polya's how to solve it. If your problem is too hard to solve, find an easier related problem and solve it first. Which I guess is sort of like applying an MVP to parts of the project as well as the whole thing.
Just be prepared that if you write a service that does not scale, that will eventually bite you painfully bad with massive amount of data going nowhere but stuck in the stupid relational database with terabytes of data.
Like most things in life, I feel like a sense of balance is the most important thing to be aware of. Jumping into code too quickly is just as bad as trying to design the perfect system from your head.
Good design isn't optimization. The trick is to do it so often as katas that you internalize it. Then you see the better way to do things and just do it. No stage fright, just action.
As a security professional as well as developer, I agree with the OP. Simply put, you're going to screw things up no matter what you do. Be smart about it, plan for the worst, and seek outside feedback into your security processes; you're never going to find all the edge cases, even if that's your day job.
That article is simplistic. Sure, write code that you won't care about in the future like you don't care about it, but if you take that approach with anything requiring longterm reliability or maintenance then you're setting yourself up for failure. Essentially: Think about it. Use techniques and tricks where appropriate, but at least consciously make the decision to do a less than stellar job and document your reasoning. A couple of lines of comments justifying some weird and verbose approach might show to others that it wasn't the lack of mental capacity to come up with another implementation.
I believe the spirit the article was written in has value. Obviously one should use common sense and still apply the best practices that they know of at the time.
The Bad Guys want you to feel insecure about your work, your position, your relative standing, and everything else because their worst nightmare is that software engineers and scientists and thinkers wake up and realize how much leverage they would actually have if they were organized and capable of looking out for their own interests. We'd reshape the entire business landscape, and the power relationships between us and them would be inverted.
They prey on the insecurity of the smartest people. It makes us easy to take advantage of, and compromises almost all of our leverage.
Every time you let them sit in your head and natter about how your work isn't good enough because it doesn't isn't in accord with what they see as "professional", you're letting them win. The problem with assholes is that their imprints live on even years after you get away from them. It takes conscious effort to get that lingering cognitive load out of your mind.
We need to step back and simplify: solve problems, and do it well. (This includes documentation and testing, when appropriate.) Make stuff, make it good, make what's good better. We need to get back to that, rather than slugging it out over "agile" and TDD and nonsense. Zed Shaw got it right: http://programming-motherfucker.com/
I've been staring at your comment and I really can't figure out how to parse it. You're rambling like a crazy person and I can't tell why. Are these supposed to be real people? Some fake force you should use as motivation? Are you honestly saying people have 'nightmares about thinkers waking up'? And come on mailing lists to encourage flame wars?
Really? From my experience the "Bad Guys" don't give a shit about code quality and will shower you with praise if you give them the crappiest code possible, as long as you make the changes they want 5 minutes ago. This article is really talking about the insecurity that other programmers inculcate, because we're all very smart and all very competitive.
Competitive to what end? There is no hard limit on the amount of code that can be written. If I write something that is not great, it doesn't prevent you in any way from writing something amazing, so why concern yourself with what I am doing at all? In my experience, the only time I start to become critical of other programmers is when I feel insecure about my standing, like in the workplace, which is an environment that is fabricated by someone else (earlier referred to as "Bad Guys").
With that, I'm inclined to agree with the parent, though perhaps his use of Bad Guys does detract from the underlying message. I don't think there is some deep plot by born-evil people to keep programmers down, but I agree with the point that we could all do much better by working together in a positive way instead of trying to out-shame each other in hopes of capturing the top prize of impressing someone else.
The Bad Guys don't care about code quality, but they want programmers to be insecure. They do, however, play divide-and-conquer games against programmers and encourage our own cannibalism (e.g. long email flamewars about tabs vs. spaces) as well as that rockstar/ninja bullshit.
Executives don't care about that specific flamewar (or even know that it exists) but they like creating environments where we slug each other over minor, superficial differences in coding style because (a) it makes us look stupid and petty, and (b) it tires us out and makes us even easier to steal from.
Programmers are often oblivious, when they find themselves in work environments that are designed to play divide-and-conquer games against them, to what is going on. Executives often enable/encourage the worst traits of programmers in order to weaken the group.
Please seek out a therapist to talk to. You can't be happy with the level of anger and resentment that you seem to have right now. At first I thought you were an attention seeking jerk, but after reading your comment history, I think you have gotten yourself into a bad place in life. Please consider it.
Wow. When are you going to post a comment that isn't about Our Malicious Overlords?
The people who promote careful programming methodologies aren't trying to make people miserable. In fact I'd lay half the blame with the OP, who needs to rein in a tendency to overthink things. We don't need a villain here.
The Bad Guys are plentiful and they include scope creepers, late/non payers and idea guys offering equity.
Our tribe (to borrow from your parlance) is goodhearted and kind and usually sees the best in people.
That is until we are crushed under the disillusioning reality that the Screwheads (to borrow from HST's parlance) rule the world and will exploit us instinctively. Our relationship with the Bad Guys/Screwheads is no different than the lion and the wildebeest.
Fortunately we can outsmart the bastards and destroy their outdated business models by harnessing the power of networked machine intelligence.
Ironically, I think this is something that affects seasoned programmers more than new ones; the more you know about the trade, the more voices you have saying "no, that's wrong! Don't do that!", which can freeze progress. The way I combat it is by writing down pseudocode in my source code - literally just english, non-compiling pseudocode - which I then "refactor" into working code (thus the first "green" is "it parses"). By making step 0 the expression of the idea rather "writing the fist line of code", I can get right into the process rather than getting hung up on the "how".