So, I agree with this article in spirit. Lots of programmers could've benefitted from a more programming centric approach rather than a CS approach. However, this bit gave me pause.
" I cannot tell the difference by watching them develop software."
I can't disagree with this more. While this may be true of students who were middle of the road students in CS programs. I can't definitely tell the difference between people with a formal cS background and those without in my daily work. I work with a handful of extremely talented self taught programmers but there is definitely a difference between the way they attack problems and think about coding versus the CS folks. Not to even mention the programmers I've worked with who have EE degrees. Those guys think about things and code in an entirely different third way.
All of these people / approaches are necessary... and none of them are better than the others... but pretending like they don't do things different because you want to feel like you don't need a CS degree is disingenuous.
Add me to the list of people who are curious and don't agree at all with your claim that people with CS background approach regular problems in a fundamentally different way. The only times when the CS folks' approach differ is when they can reduce the unknown to a known - finding the least wasteful way to cut raw materials(knapsack); modelling problems as graphs/trees and then applying well known, efficient algorithms etc.
From what I have seen, the ratio of non-clever to clever code in a typical software is 80:20(I am being conservative. It's more like 95:5). The 80% doesn't need cleverness - it needs a lot of discipline and proper abstractions. CS doesn't teach you discipline or proper abstractions. Most of the projects in a CS curriculum are small, done in small teams or solo and are thrown away as soon as the course requirements are met. The higher level CS projects exist just to prove a point(research), or doesn't exist at all except in theory.
Something that no one is acknowledging here is that a "CS" program isn't a uniform thing, and that people who come out of a "CS" program have not uniformly learned what it did have to teach.
I never took the full CS program, but I hit most of the core classes while studying Cognitive Science. By far the most valuable class sequence I took was compiler design; learning HOW a compiler takes code and turns it into assembly language was a revelation to me, and I was able to "see" the relative optimization of algorithms much better after taking that course.
Will I ever need to write a compiler? Probably not, though I have written several small interpreted scripting languages/DSLs. But taking the class expanded my mind in a way that grants me insights a LOT of self-taught programmers I've worked with never seem to have.
Does everyone who takes a compiler design class gain those insights? No, certainly not. It's possible to muddle through just about any class without REALLY understanding it and pass -- some more easily than others.
The weeder classes in CS at my college were tougher than many, though, including one that actually required each student to write non-trivial programs in assembly language.
But back to your comment: It's not that all code needs to be "clever." A friend of mine once CRITICIZED a piece of code for being "too clever," and he was right. "Clever" isn't a goal. But sometimes the straightforward approach made by someone who is good, but self-taught, isn't as good as the equally straightforward approach by the self-taught AND CS-educated programmer.
>The higher level CS projects exist just to prove a point(research), or doesn't exist at all except in theory.
Real higher-level CS projects frequently involve interesting graphics research, which (also frequently) ends up working its way into commercial game development.
I don't have any clue what you mean by "doesn't exist at all except in theory," since even if you're building advanced data structures that you could otherwise pull from a library, you're building something "real" that could actually be used.
I think you are arguing against a claim I didn't make. Your first half of the post about compiler classes and other tougher courses are giving me the perception that I somewhere claimed CS education isn't useful. I didn't make that claim. I was responding to the claim about CS and non-CS people taking different approaches to problem solving.
> But back to your comment: It's not that all code needs to be "clever."
By clever, I meant code that isn't routine. My definition of clever will include dynamic programming, reducing NP complete problems to known algorithms, writing a parser which takes xml as input and produces python dicts("writing a parser is simple" you say. But compared to the rest of the code in a typical project, it does count as clever)
> But sometimes the straightforward approach made by someone who is good, but self-taught, isn't as good as the equally straightforward approach by the self-taught AND CS-educated programmer.
It's not me who was making general claims. In my post, I did point out that about 20% of the time, CS background is very useful. The OP made the claim that CS and non-CS approach differs in general, which I don't think holds true.
> Real higher-level CS projects frequently involve interesting graphics research, which (also frequently) ends up working its way into commercial game development.
CS researchers have a lot of commendable qualities, but that requires a different set of qualities than a regular software development project, and CS research doesn't hone their skills as far as regular software dev is concerned.
Look at the code from the academia. More often than not, either there is no code(hence the comment "doesn't exist") or it's spaghetti. I don't see how that helps you write code for the regular projects where you work with teams, code isn't thrown away and you are expected to maintain it. Now, I am not saying CS researchers can't work that way - I am saying what they do for research doesn't help.
To extend on your points, I believe the difference is smaller in practice than in theory.
The biggest difference is that rigorous CS program will drill this proof-first, implement-later habit in you through repeated exercise. This is very valuable when solving something difficult because you will end up with many trial/errors, and it's much faster to iterate in your head than in an IDE. This habit is also difficult to acquire without deliberate and repeated exercise.
Most other differences are just difference in experience. It'll take a smart programmer+ no time to learn enough about CS theories to adequately solve that 5% of the most difficult part of the job.
+ By smart programmer, I mean someone who have enough intelligence/discipline to graduate from rigorous CS course, but did not.
A formal CS background gives people a very valuable toolset with which to program. It's something you can't fake, and if you know what to look for, it's instantly recognizable.
But if you don't have a CS background, yeah, I could see why it would all look the same to you.
A CS person can easily learn programming; it's second nature to them. But a programmer does not learn deeper theory as easily. Of course it can be learned, but that's why they teach CS at universities and not just programming—it's a much more difficult and more fulfilling subject, in my humble opinion.
To be fair to academic code, it's typically used once to prove a point and then thrown away. It's a lot like an R&D project any of us might do that will either be rewritten later or just used to test a theory and then forgotten.
I think some more fairness is needed here - Academic code is often bad in absolute terms, but excellent if you understand the requirements and process that produces it.
Code developed by actual academics is often terse, elegant and small; produced either due to a sudden flash of enthusiasm or because of a deeply held and significant urge to demonstrate a point. This kind of code is often at the core of what is known as "academic code".
The bulk of "academic code" is developed by a sequence of postgrads, pursuing individual goals and code is handed round with a mix of suspicion and over enthusiasm, and dropped and adopted according to the whims and short term needs of semi engaged investigators who are make do and mending with budgets and partners. So, by any sane standard it's bad.
On the other hand, it isn't meant to be adopted and used in the long term, and if you are looking at it at all it's because it does things that will be very expensive to replicate, and no one can afford to do a clean rebuild on. So - don't dismiss it if you can't afford to bin it.
Not all comparison are good. I agree that playing music requires skills that you probably don't have if you only studied art history, but this is absolutely not true when it comes to CS and SE. CS and SE both have to do with abstraction, languages, logic, models ...
The skills of "programming in the large" are hard-won through experience. There is no good "theory" that will help you structure a large program (despite many languages from academia making the claim of good structure). That's just one example.
In my experience, it's easier to teach a programmer CS theory than the other way round. At least the programmer knows what he doesn't know.
I think you misunderstand what I mean by "theory" and "theoretical background." Knowing how a computer works from the silicon level up to the operating system helps you design systems, and starting with that foundation helps you build better systems. You can get the same experience after a theoretical education, but you can't fake a theoretical basis from simple experience. You're right that you can learn it, but in my opinion, having the theoretical foundation is key to getting the right type of experience, and also helps you immensely along the way.
All I know is that I look for it when hiring. A Berkeley, Stanford or MIT CS student has a very high weight. They still have to prove themselves, but they definitely have a head start in my book.
I'm not sure I agree. For practical programming, design is one of the most important skills that you need. Code that is ugly is automatically unmaintainable, no matter how theoretically sound. The text editor is your canvas, it is your job to turn out a work of art.
I believe this is why so many without strong CS backgrounds are successful as programmers: They bring the design skills often lacking in CS graduates.
At least at my university, you can't get a CS degree without a significant amount of programming. Everybody--even the theory people--gets a thorough background going all the way from high-level programming through assembly and even a bunch of EE (it's technically an "EECS" program). Then everybody who isn't specializing in EE or very interested in CS theory does a lot of programming in more advanced courses. On top of this, most people work on some research which also tends to involve a significant amount of programming.
Really, it's not like saying an Art History major could easily learn to paint as much as saying an "Art Practice" major could.
Also, I've found that more CS-oriented people often have a good grasp of software engineering--designing programs, keeping them maintainable, ensuring correctness and so on. On the other hand, non-CS people tend to lack knowledge of theory unless they go out of their way to learn it (and most, unfortunately, don't seem to). It's much easier to get by programming at some company without knowing any theory than it is to learn CS without knowing how to program.
Now, there are obviously CS people who spend very little time programming. But, in my experience, they're relatively rare and tend to stick to academia. Really, they're more like math major who happen to like CS than anything else. The ones like that I've met here also happen to be some of the smartest people I've ever talked to, but that could just be a coincidence.
EE programmers are fun... just model it as a state machine! The best part about writing your code as a state machine is that you can then easily translate it into VHDL for implementation on an FPGA, or even into silicon.
It is hard to answer this because a lot of the trite answers are indeed false. A computer science student may be more able to tell you whether an algorithm is O(n^3) or O(2^n), but the normal (and experienced) programmer will be able to tell you either is "slow" and fix it just as quickly.
But there is a style of thinking that can come out of a study of computer science that can be very difficult to obtain on your own, and enable you to build larger and better systems than all but the very, very, very best of self-taught programmers, and while it's hard to put that difference into words, it's mostly the study of maintaining invariants in the code from both a theoretical and a practical standpoint. Or, if you prefer, a way of thinking that helps create and enforce a mathematically-strong form of conceptual purity in your code.
Those who don't have this background, and I very much include people who took the courses but just sort of skated through without absorbing anything, will often have problems with any API I create that requires certain constraints, such as being careful at what point they access local information vs. remote information. Their use of the APIs will be sloppy and hacky, because they don't really understand how they work or what they are for. The constraints I am thinking of are purely technical, a particular server/client split, so when I say you can not do X it is not merely me being an academic prick, it is because it is actually impossible to do X because at the time your code runs you are literally in the wrong place. Explaining this fact is easy, but explaining how the system conceptually wraps around this constraint and works the way it does is a challenge.
And APIs designed by such people, while they may get the job done, tend to be very brute force (for lack of a better term) and to lack any sort of firm foundation, such that the moment a requirement even slightly changes we have to make massive (and often hacky) changes to them.
Unfortunately, it is impossible to provide examples in the scope of a single post, because all small examples will not show the issue. It's a larger pattern of issues that tend to start interacting with each other, which is where the real problems emerge.
It is also the case that a proper path chosen through a computer science program will take you through some eminently practical theory that will make you a vastly more powerful programmer, and is very hard to pick up on your own. By far the biggest example of this is compiler theory. If you are currently in college and still have the opportunity to take your local compiler course, take it. I don't write very many "compilers", but I have now written quite a few "interpreters" and it has enabled me to complete projects that could not have been completed any other way. Getting a formal grounding in signal processing is also a good idea, that one can be hard to pick up later and has surprisingly useful intuitions for a lot of high-speed networking tasks. A formal grounding in networking can be good, though a lot of courses unfortunately seem to just march through TCP and the OSI model, which you could relatively easily just read about.
The fastest way to obtain this basic understanding if you are a good programmer but lack the formal education is one of really, honestly working through SICP (and not just reading it), or becoming fluent in idiomatic Haskell, with special concentration any time someone talks about "enforcing invariants via types". (Personally, I believe Haskell has completely supplanted Lisp as "the language to learn to expand your mind even if you have no intention of using it", but be sure you stick with it for a bit. Learning how to string together a couple maps and a fold is not where the interesting stuff is, it's what the interesting stuff is made out of.) Also, break yourself of the subconscious idea that academic === useless. As someone who tends to straddle the border I will completely agree it isn't all useful, but it isn't by any means all useless either.
And just let me reiterate as my closing point that it is absolutely possible to go through even a very good Computer Science program and fail to absorb the useful lessons it has. Presumably these are the people claiming it's "useless". I have to admit I tend to not have a high opinion of people who managed to go through a solid program and come out with nothing. (There are also some complete wastes of programs, so YMMV.)
Very, very insightful post. Thank you! To add a little personal bit, I use Haskell daily in my research. I also do web programming on the side in Rails. After figuring out Haskell, and then learning idiomatic Haskell (along with monads, monoids, functors and friends) my way of writing Ruby became much different. I'm more cognizant of patterns in Ruby as they relate to Haskell (as they relate to formalisms in computation). For example, handling nils in Ruby can follow patterns of the Maybe monad in Haskell.
This isn't to say that Haskell is the only mind-expanding language out there, but it sure is good and it worked for me. I think it makes it especially easy in this regard over ML or Lisp in the "mind-expanding" game because it has so many formalized computational concepts that are first-class and upfront. That's not to say that you can't expand your mind in other languages, but Haskell can really help you out if you're willing to roll with the learning curve.
I would add that part of the reason I think Haskell has supplanted Lisp is that so many of the concepts of Lisp have been absorbed into mainstream languages that the distinctiveness is greatly reduced. Macros are still mindblowing, but much less so if you've used Ruby or Python or Perl than if you're a pure C programmer. In 20 years, I suspect modern Haskell will be "less mindblowing" for the same reason. It's not that Lisp has gotten less good or anything, it is that it has mostly won.
Macros are still mindblowing, but much less so if you've used Ruby or Python or Perl than if you're a pure C programmer.
I disagree with this statement. Python's introspection, first-class functions, magic methods, and duck-typing add a lot of the dynamism of Lisp, but every time you run up against something that needs to be a macro, it's a dead end. C has a rudimentary macro system that can get you a little past that point; for example, it's not too difficult to add a foreach construct to C that looks like this:
On a sidenote, it's kind of sad that a programming layer just above assembly language created 4 decades ago has better macro support than some of the most popular modern languages.
On a sidenote, it's kind of sad that a programming layer just above assembly language created 4 decades ago has better macro support than some of the most popular modern languages.
I disagree. In Python, you have much more advanced metaprogramming facilities, depending on what kind of effort you wish to go to. You have the normal introspection, magic methods and metaclasses as you mentioned (which, IMHO, are in themselves already much more powerful than what you can do with the C preprocessor). But you also have access to exec and eval which lets you do all kinds of crazy stuff that isn't possible with C macros. Using operator overloading and classes, you can even create a lot of new syntax which isn't possible in C[1].
Finally, if you are really determined, you can even hack semantics of existing Python constructs by instrumenting the bytecode. For example, I saw a hack which adds tail-call optimization to Python functions this way (iirc as a decorator).
I havethat's usages. You are falling for he fallacy of believing that because you are a talented that only people with the same experience and knowledge can be talented. This mistake I see in the many the recruiting articles that make it to HN that boil down to "how to here someone go is exactly like myself".
I have worked with extremely intelligent CS graduates. When it comes to the really involved algorithmic work they leave me in the dust. However every programming job I've ever had has been focused on the other stuff like writing tests and building clean abstractions and maintainable code 99% of the time.
When it comes to this stuff CS grads are no better than any other programmer. In fact, new graduates are often worse because they've never had to build and maintain massive systems over any significant period of time.
Person A spends four years getting a BS in CS at a top-tier school, learning about programming at least for a few hours a day on average, with the benefit of a well-considered curriculum and instruction by wizards.
Person B spends four years working full-time on something interesting at Google, which probably gives her more total hands-on-keyboard time, and also access to some minor wizards, although they may not care so much about teaching her.
Let's say that both of them also spend a bit of time on the side learning programming things not school- or work-related.
If both of them have an equal thirst for knowledge, I just don't see why person A is likely to become a better programmer, or why B would fail to pick up the style of thinking you described (which is common, in my experience, among good programmers.) I honestly think that you're mixing up the consequences of {smart, curious, motivated, spends a lot of time programming} and {took a CS degree}.
> Person A spends four years getting a BS in CS at a top-tier school, learning about programming at least for a few hours a day on average,
Real world might be different, but I don't think a CS degree should be teaching programming at least for a few hours a day. IMO that would be a total waste. There are bazillion of things to learn - database concepts, discrete maths, networks, ai&ml, digital electronics, some basic circuit theory, operating systems...There is programming involved in almost all of the courses, but the purpose isn't to learn about programming. When I am learning about MVCC, I am least concerned about learning programming, but the MVCC concept itself.
It would be pretty tough, although you can replace "Google" with "any roughly Google-quality set of coworkers and projects." But the original question was whether it's really "very difficult to obtain on your own" the sort of perspective and knowledge you get from taking a CS degree. I doubt that, and I think that most people who are similarly smart and spend a few years working hard with other smart people will pick up many of the same skills.
I've stabbed at it, but what came out had a circular dependency in it; the only way to understand the text that resulted was if you already understood the text. About half the stab attempt is at http://www.jerf.org/iri/blogbook/programming_wisdom , with another half just sitting on my hard drive (which is what has the stab at a discussion on exactly what I personally meant by conceptual purity), but until I figure out how to get past that circular dependency it's probably not going anywhere. And I suspect what I'm trying to do there is simply not possible.
Same here. I think the idea of a BSc in Software Development is excellent, and I think some colleges are starting to think along those lines. For instance, the SaaS class from Berkeley on Coursera would have been far more useful to me than the circuit design and formal theory classes I had to take.
However. There is definitely something to be said for SOME kind of structured education for developers. The author's anecdotal evidence notwithstanding, I have met many aspiring self-taught programmers who just don't have it. There seems to me to be a strong correlation between a person's drive to learn something and their willingness to pursue a formal education... not surprising if you think about it.
I also know an absolute genius programmer who is 99% self-taught. But just because people like Wozniak exist doesn't mean they're the norm.
For what it's worth, Wozniak actually did EECS at Berkeley ;).
In regards to the SaaS class: I know a bunch of people who took it before it was offered online. Perhaps surprisingly, most of them did not find it useful. The issue is that they picked up everything taught there either on their own or in internships; they really didn't need to waste a whole course on it. That said, the particular people I talked to are some of the better EECS majors who tend to have significant projects of their own and good internships, so there is certainly some bias.
No need to limit it to self-taught/trade-taught programmers, CS people, and EE people.
I once worked with a brilliant programmer who was studying Classics and English Literature and he had an entirely novel approach too, and brought real value to the team.
That's the cool thing about programming -- it's an abstract thinking skill, so anybody with any sort of formal training will bring their specific ways of working and thinking into the game.
I can't talk for the parent, but one significant way I expect people with formal training and people without it to differ is in how the knowledge of data structures and algorithms affects their work.
If you stumble upon a problem that cries for a trie or a splay tree and you don't know they exist, you'll have a very difficult time solving the problem with adequate performance.
If you are lucky and dedicated and talented you might end up with something similar, but it'll take you a lot longer than one who already knew they were there and how and why to use them. Likewise, if you have been trained in developing algorithms, you know what are the important things and which aren't, and have a toolkit to select ideas from.
More than studying, learning a good book on data structures. That, and the intractable quality about learning to design systems and how invariants are involved in the design jerf talked about up there.
> I can't talk for the parent, but one significant way I expect people with formal training and people without it to differ is in how the knowledge of data structures and algorithms affects their work.
And how often in your experience you stumble upon these kind of problems? In my experience, the clever parts are about 5% to 20%. Of course, there can be projects where the clever parts outnumber the non-clever parts, but we are talking about norms, and as you said, exceptions don't prove rules.
The question posed was "how do they differ?" not "how important is that difference?". If you ask me the latter, I'd say that for many domains it's not that important (see the caveat below.) On the other hand, for Google and Facebook and similar companies it's certainly very important, which is why all their interviews are mainly about how well you can reason about algorithms and data structures.
Caveat: These problems might not happen often in less data intensive domains but, when they do happen, they are certainly very important in my experience.
> The question posed was "how do they differ?" not "how important is that difference?"
And the question arose from the claim that the formally taught and self-taught programmers take different approaches in general. It goes without saying that a problem that can be solved effectively using a trie will be approached in 2 different ways by someone who knows tries and someone who does not. The claim made in the OP was broad, and I am saying about 80% of the time, an auto-didact and a CS person will solve it the same way. Claiming that because sometimes a CS person can use insights which the non-cs guy doesn't have doesn't equate to different approaches.
The fact that 80% of the time the approach is not important to get the desired result because the task only operates over small n or similar does not mean that the approaches are equal.
It might not be needed, but it's about the approach. You don't need all the tools all the time, but knowing what patterns are available and having a good understanding of why you would or wouldn't use it means you approach a problem starting from a different place.
It's possible to get the same end result most of the time (especially if the end result doesn't require the "clever" solution), but I would also agree that there definitely is a difference in approach that is discernable by watching someone work.
People talk about the types of programmers you company needs, things like:
Starter
finisher
bug fixer
architect
In many ways I think these are the sorts of things that are influenced by your background. People with a CS background tend to be better at the architecting side of things in my experience. The self taught are better starters because they are super comfortable learning new languages and enjoy the thrill of the new stuff. Some of the best finishers I've ever met tend to be EE folks.
I think this is possibly as much about their background as it is about the personality types that choose these different paths. That said, lets look at the coding style. The EEs I've worked with have all written extremely "simple" (This is not derogatory) code that was easy to verify and tended to not use as many "high level" features. The self taught programmers I've worked with write amazing code using some cutting edge shit that looks great and usually works great... but often don't think about optimization until the very end.. some times to the detriment of architecture and design. The CS folks will tend towards over optimizing up front and getting caught in the pre-optimization trap. They may over design it up front and tend towards some middle ground between "simple" and "cutting edge" that half the time ends up being worse than either of the other methods.
This is of course an over simplification and doesn't fully capture all of the differences I might've noticed.. it's simply an example and obviously I understand these are generalizations that won't always be true, but it's clear there are differences.
Additional example, if you want to know what a bunch of different grad students specialize in stick them together on a moderately complex project and just watch which items each person obsesses about. Some will obsess about network latency, some may obsess about the cache performance, others about security. We need all of these people... but it's clear they will hone in on different items.
> Some of the best finishers I've ever met tend to be EE folks.
That's been my experience as well, but I think it's mostly because of the three types, EE's are the only ones used to making schedules and sticking to them.
" I cannot tell the difference by watching them develop software."
I can't disagree with this more. While this may be true of students who were middle of the road students in CS programs. I can't definitely tell the difference between people with a formal cS background and those without in my daily work. I work with a handful of extremely talented self taught programmers but there is definitely a difference between the way they attack problems and think about coding versus the CS folks. Not to even mention the programmers I've worked with who have EE degrees. Those guys think about things and code in an entirely different third way.
All of these people / approaches are necessary... and none of them are better than the others... but pretending like they don't do things different because you want to feel like you don't need a CS degree is disingenuous.