Hacker Newsnew | past | comments | ask | show | jobs | submit | ejames's commentslogin

More difficult to work with.

It's not a problem for the computer if you have a lot of code in a single file, but it is a problem for the computer programmer. If there's a lot of functionality in a single file, class, or other grouping of code, that makes it much more difficult for a human to understand and remember the details.

It's easier to work with a project if you can break it down into small pieces that are each individually easy to understand, so a goal of good project organization is to make your code out of small parts - small files, small models, a small number of lines of code - and have the parts be easy to distinguish and remember.

If you split one big "User" model into separate bits for billing, authorization, and user settings, not only is it easier to understand what parts there are, when you need to go in and make a change to the billing code, you immediately know that 2 out of 3 of the pieces can be safely ignored.

Similarly, if you take some very common functionality that models often have and generalize it, you only need to learn the general version once and then it applies to each of the parts. That's what the article describes. Many models are "Searchable" or "Taggable", but you only need to learn how searching or tagging works once, and the same search or tag code applies in multiple places.


Excellent. I may have to read more of this man's work. What works best for humans seems to frequently be given short shrift and the importance of it undervalued or missed entirely.

Thanks.


Take home exams are somewhat common at modern universities, and in fact are sometimes used as an anti-cheating measure.

Rather than having questions which can be easily answered with access to research materials, the exam is designed to be difficult even if you have the textbook open on the desk right next to the exam. Take-home exams often specifically grant permission to use the textbook and any other class materials.

Because a take-home exam is built on the premise that the student will have access to all of their materials, the professor writes the exam expecting that you have attended all the classes, read all the textbook chapters, and understood all the notes, so the exam is much more difficult!

It's also meant to make exams more like real work. Nobody at my company gives a damn if I need to crack open a math textbook to find an algorithm, or Google something - but a real job requires that you can understand and synthesize the information you find. You can't build an entire (...good) product out of copy-and-pasted answers from Stack Overflow but you can look up specific issues or points where you get stuck.

Remember that we're seeing this story because the students failed to get away with cheating - in part precisely because of the nature of the exam. One of the questions is an open-ended invitation to pick two events and explain them, and it's very suspicious if a group of students all pick exactly the same two events and present similar-sounding explanations.


>the professor writes the exam expecting that you have attended all the classes, read all the textbook chapters, and understood all the notes //

As opposed to?

Seriously the exams should test your knowledge and application of elements from the whole range of the course material. Giving that as a reason why you can take the exam home and [have someone else] do it sounds entirely absurd to me.


Having the legal right to do a thing does not mean that you are invincible to criticism for exercising that right. You have the right to freedom of speech, but the things you actually say may be foolish or wrong; contrarily, cheating on your spouse is not a crime, but doing so still makes you a worse person. You have the right to keep all your money instead of giving a penny to charity, but being charitable is better. "Legal" and "good" are not the same thing.

Denis-Courmont may have licensed his code under GPL for a reason, but it can very well be a bad, zealous reason. Indeed, I would expect that almost every person who truly is a zealot and a bad apple would choose to license their code under GPL. The GPL is a license that demands total obedience to a particular ideology of software distribution, and requiring that other people obey your ideology in every detail is the defining characteristic of a zealot.


Calling him a zealot just for using the GPL seems a bit unnecessary to me, but whatever. It does not matter what his reasons are for it, he is allowing people to use the code he wrote under a certain set of conditions, which some people have not been honouring. I don't believe there is anything wrong with him calling them on that; why should he just sit there quietly while other people violate his license and profit off his work?


>why should he just sit there quietly while other people violate his license and profit off his work?

Gee, I don't know. Maybe for the good of the hundreds of thousands of users of iOS/VLC? Maybe because the other contributors had agreed to this and didn't care for the technical violation, especially since both the code was available and the app was free? Maybe because also working for Nokia seems like a huge conflict of interest?


Maybe Apple and Microsoft should release all their software under a permissive license for the good of hundreds of millions of users. Is that what you are suggesting? I do not have any problem with people/corporations releasing/selling their code as they see fit, but I do take issue at people feeling entitled to set the terms for other people's code. If the other contributors do not mind the violation, they are free to remove his code and release their code as they see fit.


Using the GPL is not really comparable to saying something foolish or wrong, and is certainly not comparable to cheating on a spouse. Such arguments reek of anti-GPL zealotry.


Hmm. I appreciate the idea of a standardized way to modify a JSON document, but I'm not certain what problem it realistically solves. Can someone who's worked with APIs that accept updates give a code example of something that would be better if you accepted patches instead?

Other commenters have brought up size - that the patch must be quite a bit smaller than the whole document in order to gain a benefit - but I'm not sure it's useful even then. JSON is typically the representation of an object for transmission over the wire, not its final representation on the server.

I have a Rails servers with a JSON API, but it stores information in a SQL database where the columns roughly correspond to the JSON keys. I'm not actually storing JSON in the database and the mapping of JSON key to database column is not always one-to-one. That means if I want to accept a patch for an object with JSON Patch, I need some way of applying the patch "upstream" to the SQL row that is the source of truth for the object. And, of course, for a database with a schema, only a strictly limited subset of potential JSON Patch objects submitted can actually be applied.

The architectural benefit of accepting JSON Patch as an update is that "it's just JSON", but in order to apply a patch on pure JSON, you must have pure JSON and store pure JSON. It's now common for servers to use JSON but that doesn't mean it's "JSON all the way down". In the case of my Rails project, I would need to generate the JSON for an object (or retrieve it from the cache), apply the patch to that JSON, then treat the result as if it had been submitted as an entire document to the update endpoint. Instead of parsing received JSON, I need to generate JSON, process a patch, then parse the result. Whether or not the client has to deal with the entire JSON document, the server has to do so.

Now moving the burden to the server can actually be a very important improvement if that's where you want to do the work, but I don't know that you need a new standard of JSON document to do that - if you want to perform small updates on large objects, you can write the server such that clients are allowed to omit key-value pairs that are not to be changed when sending JSON to update existing items. Perhaps I'm just dense, but it seems like you only need to iterate through the keys that are included and update only those fields.

JSON Patch is a defined format for doing that but it adds a layer of abstraction to the operations, when you actually would want clients to be concrete in specifying keys and values so the server doesn't have to perform lookup to figure out which value is under which path.

Likewise for the concept of "synchronizing" structures, the problem is that you cannot apply a patch correctly unless you start with the same JSON before applying the patch. I don't know if the speed gain from sending patches instead of entire documents justifies the extra reliability work you need to do to make sure the synchronization eventually succeeds. Plus, just as you don't save time in the code to apply a received patch unless a JSON document is the canonical "source of truth" for that object, it takes work to generate a patch for another party to apply unless a JSON document is the "source of truth" and you can cheaply produce the diff in terms of JSON. (Like any document format, you CAN process and produce the data eventually, but the question is whether it's easier than alternatives.)

It seems like this could be useful for a system where you specifically want to store the changes to an item - i.e. an audit log - but I don't know if JSON Patch is substantially better than existing ways of doing that. Before reading this paper, if I was asked to write a project that stores the changes to a chunk of JSON, I might have done something like insert a \n character after each key-value pair and store the history as commits in git. That's a hack, but since JSON is text and developers already have lots of ways to manipulate text, I'm not sure why it's necessarily better to work with the state changes as "JSON that is changed by events that are also JSON" rather than "text that is changed by events, and the result always parses as JSON", since there are already good tools for working with plain text and evaluating changes to the text.

I can see this being useful in a system where you have really set a deep architectural assumption that it's "JSON all the way down", and therefore a JSON Patch can be treated with some level of abstraction rather than just being a well-defined shorthand for sending fewer bytes over the wire. If the system is a document store that considers arbitrary JSON to be the unit of storage, then you don't need to worry about mapping into alternative storage formats. However, that seems like a very specific subset of the architectures in the world of "servers that communicate with JSON".


> Can someone who's worked with APIs that accept updates give a code example of something that would be better if you accepted patches instead?

Concurrent edition of tabular data by several users.

User loads a HTML <form> with a bunch of widgets into her browser, edits some of the data and <submit>s. The usual implementation causes all data submitted via HTTP POST request, as simple KEY=VALUE dataset. Should two users send POSTs of same resource (same URI) concurrently, it is not clear what are real changes and what is unchanged, nor how to apply it to the resource.

What I'd like to do -- and indeed, some parts of my software does, albeit in non-standard way -- is submitting diff, in form of KEY=<original-value, new-value>. Makes it easier for the backend to serialize users' changes, and either apply them in atomic way or reject just the conflicting ones.


Thanks for the example. Receiving a patch does let you know just what change the user intended to make, and often you actually care about the change, not the before or after.

As I keep looking at this, it seems that it's most valuable when you consider the patch as an element of an event-based system, where you're storing or operating on changes rather than just the data. The reason it helps with a bulk editing process is that you want to know what changes Alice and Bob made if they both submit at the same time - operating on diffs simplified the system. For other systems where you operate on diffs, like an audit log, it's helpful to have a first-class format that defines the diff on a JSON document.

I think that's the biggest caveat I'm seeing with the proposal. It's pitched as a way to handle HTTP PATCH requests, but a format that defines "diffs on JSON documents" is most suited for systems that primarily store JSON documents and diffs on JSON documents - it is much less broadly applicable for "HTTP servers that accept JSON data", since frequently they only work with JSON over the wire, not as the ultimate source of truth. If you don't store JSON documents as the ultimate source of truth or have a domain-model reason to want diffs, I'm unsure of the advantage.


Agreed, I'm excited for this format, but only because I store almost all of my state in JSON blobs.


This is why I left Microsoft. Automated testing was a separate discipline - meaning there were "dev devs" and "test devs". Automated tests were written based on what the "test devs" had time for, not on the need or usefulness of such tests for the actual code. I was hired as a "test dev" - I had no industry experience at the time and figured I would give it an unprejudiced try to see if I liked it.

I quickly realized that my job was futile - many of the "good" tests had already been written, while in other places, "bad" tests were entrenched and the "test dev" had the job of manning the scanner to check for nail clippers, or upgrading the scanner to find as many nail clippers as possible.

Here's a useful rule on the subject that I picked up from an Artificial Intelligence course back in the day: The value of a piece of information is proportional to the chance that you will act on it times the benefit of acting on it. We all realize there is no benefit in testing if you ignore failures rather than acting to fix the bugs, but in much the same way that doing nothing when tests fail has no benefit, doing nothing when tests pass also has no benefit - so tests which always pass are just as useless as failing tests you ignore, as are tests which only turn up corner-case bugs that you would have been comfortable with shipping.

If you're doing the right amount of testing, there should be a good chance, whenever you kick off a test run, that your actions for the next hour will change depending on the results of the run. If you typically don't change your actions based on the information from the tests, then the effort spent to write tests gathering that information was wasted.


I disagree that there is no benefit in passing tests that don't change your behavior. Those tests are markers to prevent you from unknowingly doing something that should have changed your behavior. That is where the nuance enters: is this a marker I want to lay down or not? Some markers should be there; others absolutely should not and just introduce noise.


I don't understand what you mean by "prevent you from unknowingly doing something that should have changed your behavior". If you do something without knowing it, how could it change your behavior? If it's a case where you should have changed your behavior, why would you prevent it?


I believe the above comment refers to regression testing. For instance, if I write a test for an invariant that is fairly unlikely to change, then the chance that my behavior will change in the next hour based on the test run is small. However, if and when the invariant is mistakenly changed, even though negative side effects might not be immediately visible, it could be immensely valuable to me to see the flaw and restore that invariant.


Yes - but the test would fail when the invariant is mistakenly changed. On the test run after the invariant was changed, you would get new information (the test does not always pass) and change your behavior (revert the commit which altered the invariant).

That is the point of the "changing behavior" rule - you do not gather the benefit of running a test until it has failed at least once, and the benefit gathered is proportionate to the benefit of the action you take upon seeing the failure. The tricky part of the rule is that you must predict your actions in the future, since a test that might have a very important failure later could pass all the time right now. Knowing your own weaknesses and strengths is important, as is knowing the risks of your project.

There are possible design benefits to writing tests, since you must write code that is testable, and testable code tends to also be modular. However, once you have written testable code, you still gain those design benefits even if you never run your test suite, or even delete your tests entirely!


Your comment reads like you can know when a test will fail in the future (how else can you know the difference between a test that "always passes" and a test that will fail in the future to identify a regression?). You may have a test that passes for ten years. When do you know it's OK to nuke the test?

Based on your follow-up, it is clear that my reading was not what you intended.


You can't know, but you can guess, based on past experience or logic. The simplest way to estimate the future is to guess that it will be similar to the past.

For example, if you personally tend to write off-by-one errors a lot, it's a good idea to write tests which check that. On the other hand, if you almost never write off-by-one errors, you can skip those tests. If test is cheap to write, easy to investigate, and covers a piece of code that would cause catastrophic problems if it failed, it's worthwhile to write the test even if you can barely imagine a possible situation where it would fail - the degree of the cost matters as much as the degree of the benefit.

You don't "know" when it's OK to nuke a test just as you don't really "know" when it's safe to launch a product - you decide what you're doing based on experience, knowledge, and logic. The important step many don't take is developing the ability to distinguish between good tests and bad tests, rather than simply having an opinion on testing in general.


Re: "The simplest way to estimate the future is to guess that it will be similar to the past."

When we say that the future will be similar to the past, for code, we really mean that the probability of certain events occurring in the future will be similar to their prior probability of occurring in the past.

In my hypothetical example of testing an invariant that is unlikely to fail but damaging if it does, it might be valuable to keep that test around for five years even if it never fails. Imagine that the expected frequency of failure was initially <once per ten years>, and that the test hasn't failed after five years. If the expected frequency of failure, cost of failure, and gain from fixing a failure remain the same, we should keep the test even if it's never failed: the expected benefit is constant.

Not to say that we should test for every possible bug, but if something is important enough in the first place to test for it, and that doesn't change (as calculated by expected benefit minus expected cost of maintenance), we should keep the test whether or not it changes our behavior.

Thus, if we could estimate probabilities correctly, we really would know when it's OK to nuke a test.


Hey Evan ;)

> We all realize there is no benefit in testing if you ignore failures rather than acting to fix the bugs, but in much the same way that doing nothing when tests fail has no benefit, doing nothing when tests pass also has no benefit - so tests which always pass are just as useless as failing tests you ignore, as are tests which only turn up corner-case bugs that you would have been comfortable with shipping.

On the contrary, my opinion is that we don't see this often enough. Our bug database shows the current list of defects, and there is very very very little data on what does work. What is test covering, and how many defects are they finding within that coverage?

If your bug trend is heading downward, is it because the test org is distracted by something, or because there are fewer bugs that they are encountering?


Hey Jonathan ;)

This is the danger of having a 'test org' separate from the 'dev org'. When writing tests is tied to writing production code, your progress in one is tied to progress in the other. If it's easy to write tests for a particular feature, then the developer stops writing tests and writes the feature once they're done with the easy tests. It's much easier to understand your coverage when you're actually working with and writing the code being covered, rather than working in some separate "test org" - you don't need to run a coverage tool, you just see what breaks if you comment out a chunk of code. If the answer is "nothing" then it wasn't covered!

At the end of the day, an automated test suite is a product for developers on your project in the same way that a car is a product for drivers. You will have a hard time making a car if nobody on your car-making team can drive, and you will have a hard time writing a test suite as a tool to develop Project Foo if nobody on your test-writing team develops Project Foo.

I now write a project where I handle both the code and the tests. In the same way that my production code is improved by writing tests, my tests are improved by writing production code. I know what is included in the test coverage in the same way that I know what I had for lunch today - because I was there and I remember what happened. Tools for checking coverage are an aid to my understanding; in a company with a separate test org, you don't know anything about coverage until you've run the tool.


> This is the danger of having a 'test org' separate from the 'dev org'.

I completely agree with you, in light of how MSFT categorizes their ICs these days. There used to be three test/dev disciplines when I started (in 2001): "Software Test Engineers", "Software Development Engineers in Test", and "Software Development Engineers" (you likely know this already, but it might be useful history for others to know). Around 8-9 years ago the STE discipline disappeared; the company hired for SDETs (like yourself) from that point on.

The big loss here was that now all STEs were expected to be SDETs - writing code on a regular basis to test the application. There were (notice the past tense) many STEs who knew our application very* very well, and knew how to break it, hard. STEs provided quality feedback at a higher level than what a unit test provides - does the application feel right? Are customers getting their solutions solved? If you have your eyeballs stuck inside a unit test it's difficult to step 30 feet back and ask yourself if you're even doing the right thing.

Nowadays I feel like the pendulum is slowly swinging back the other way, and there is less drive to have test write automation (and maybe it is because where we are in the product cycle). I understand that high-level STEs "back in the day" were probably concerned about potential career progression at the time, which might be why they eliminated STEs (I have no idea of the real reasons - they've been lost to Outlook's mailbox size limits), but all-in-all I think MSFT is poorer because of it.


I worked on enterprise projects "at a similar company" with a few hundred "top notch" engineers. We had no more than 30% coverage, most of it from SDETs. No tests were being written by the devs before checking in for months, the test devs were understaffed, unqualified and thus behind. At one point someone made a checkin that prevented login from happening. Nobody noticed for a full work week, until that version made it into preproduction and someone finally attempted to login. Apparently hundreds of mils spent on the project can't buy you a team able to write above high-school level code.

I can see the usefulness of SDETs in doing system / end-to-end testing or testing of really obscure scenarios, but most of the test writing should belong to devs. I love the Rails approach to UT, functional and integration test split. The first time you try BDD, especially if you're coming from an after-the-fact testing culture like the one above, you almost want to cry from joy. I agree that Cucumber might a bit of an overkill, but perhaps I don't get it. For a non-prototypey project you should absolutely add other types horizontal testing like performance, security..


While I agree with this description of the value of information, I disagree with your interpretation of it in this context. Consider the following, rather extreme example: nuclear power stations are equipped with countless diagnostic systems with several levels of fallback. In a well-built and well-operated nuclear power station these systems will never signal failure during normal operation. This clearly doesn't mean that the output of these systems carries little value. Surely, a test that is always passing doesn't necessarily has no benefit, you also have to consider what it would mean if it suddenly stopped passing.


You are not designing nuclear power stations. You are at best designing a piece of business software.

(If you are designing a life-critical application, the scope of this article doesn't apply to you, as is stated in the article)


I've seen the value of text formats personally.

I work mainly on an iPhone project. In order to handle customers requests for this or that custom UI feature, I invented a tool that generates something like a simplified XIB file from an image and a chunk of CSV. I made the end result of the tool a text file that the iPhone code parses.

Working in text saved a lot of time. Since I invented my own tool, naturally there were things to debug and tweak in the results, but I could do that with a text editor and commit the changes as easily diff-able deltas in git. Although I work on iPhone code, everything also has to be implemented in Android - but it's no problem for the Android developer to use the text file since it's just text.

I've also written tools for migrating chunks of customer data from an old back-end system to a new one using the new server's customer-facing API. This was partly for dogfooding purposes, since the API was new and had very suspect stability.

I wrote the tools to generate text files where each line is a JSON payload that would be sent to the server. It made everything easier to debug - examining the payloads lets you distinguish between errors in the export tool and errors in the API. The text files themselves could then become test cases if there was a bug in the API, or be quickly hacked to contain correct payloads via find-and-replace if the export tool was wrong but we still needed the migration to finish right away.


I'm building a tool very similar to what you describe for Android right now. It involves a simplified XML description of the GUI which is sent over a network to an Android device, then "inflated" to actual GUI code.

Could you elaborate about your system a bit?


It's because Objective-C methods are named according to the nouns that they return rather than the verbs they perform. For example, "[input stringByAppendingThing:thing]" rather than "input.append(thing)".

Methods are actions, not objects, so the most concise description for a method is usually a verb. Describing it as a noun instead requires adding prepositions and turning verbs to the gerund '-ing' form.

I realized this because I write both Ruby and Objective-C, and sometimes write basically the same thing in idiomatic forms of both languages. In idiomatic Ruby method-chaining, your code is a series of verbs with the relations between the actions defined by the '.' or the '()' signs, rather than by words such as 'to', 'from', 'with', or 'by' present in the name of the method.


Eh, I think that's a little overbroad. The way it works is, methods whose purpose is returning something are named for what they return, while methods whose purpose is creating a side effect are named for what they do. So NSString has `stringByAppendingString:` because you're asking for a new string, while NSMutableString has `appendString:`, which is essentially the same as it would be in Ruby except with an allowance for Objective-C's static type system.

What really creates the impression that Objective-C speaks in terms of nouns is that Cocoa tends to promote immutable objects more than Ruby does (e.g. the only way to get an immutable string or array in Ruby is to freeze a mutable one, while you'll almost never get a mutable array in Cocoa unless you create one yourself), so you probably do spend more time asking your objects for other objects than you do in Ruby.

Although the verbosity can get overwhelming, I actually like this about Objective-C. In terser dynamic languages, I'm constantly having to confirm (either mentally or in the docs) which methods mutate and which return a new object. Cocoa's naming conventions mean I pretty much never have to do that.


The guidelines for Ruby are to add a bang (!) to any methods that mutate the object rather than returning a new one. That's not strictly followed, though, but for most of the commonly used standard library bits, you can be fairly certain that that is the case.


In practice, even in the standard library, this isn't followed often enough to rely on. Here's a (possibly incomplete, since I'm writing this on the fly) list of bangless mutating methods just from Array:

  pop
  push
  shift
  unshift
  <<
  clear
  replace
  delete (and friends)
  keep_if
As an even more extreme example, IO contains precisely one bang-method, despite the fact that probably 75% of IO's instance methods are destructive.

The general rule seems to be that if there's a mutating and non-mutating version of the same method, the mutating one will get a bang, but when there's a mutating method with no counterpart, it might get a bang but probably won't.


The guideline is: if your method does something that the programmer should think twice about or shouldn't use without proper knowledge (e.g. didn't read the docs), use !. An incomplete case of usages:

  - There is a safer alternative (e.g. mutating vs. non-mutating or skipped validation)
  - It should only be called once in a process (e.g. Padrino.start!)
  - It is non-reversible (many statemachine libraries use action! as the way to invoke state transitions, which might not be reversible)
This doesn't mean that every method needs to be suffixed by ! if it does something destructive. `delete` in the context of an ORM is standard, so it doesn't have a bang. The whole point of `pop` is to manipulate the receiver: no point in warning about it. IO is always destructive, so ! doesn't make sense either.


Very well said. I think this also promotes a mindset of making methods that either mutate state or build and return an object. It's often very difficult to follow code that has lots of methods that do both.


Have you read http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom... ?

Yegge basically completely agrees with you. Once I started thinking of OOP in these terms it helped me, as a programmer, a lot.


Thats a hilarious post but it sounds like Steve would love PHP. He could use nouns (objects) when he wanted yet add global functions (verbs) with no attachment to objects. I personally think that's a great way to make a terrible mess, but perhaps he knows something that I don't.


Interesting observation. It is called "Object"ive for a reason :)

I wonder if we can relate your observation to the fact that "messages" (nouns) are preferred to "methods" (verbs) in Obj-C.


It's hard to make accurate, general statements about a group. It's also hard to tell good programmers from bad programmers. So it's very hard to say whether Rails programmers in general are good or bad.

I can tell you, however, that it's quite common for Rails programmers to not know much about Ruby except for the parts used by Rails. In the U.S., Ruby was popularized by Rails, and very few programmers learned the language separate from Rails. I'm unusual in that I picked up Ruby first (while visiting Japan) and learned Rails much later.

Rails is much more than a DSL - I would call it a framework, which includes several DSLs as sub-components - but for a pretty broad range of the complexity of your web application, you spend more time and code dealing with Rails library functions and DSLs than with 'pure' Ruby. In most cases, that's the point - Rails is useful precisely because it gives you library functions, DSLs, and middleware components that deal with common web app issues. Rails is a good framework precisely because you can use the framework instead of building things from scratch in pure Ruby.

Because of those factors, many Rails programmers don't know the underlying language of Ruby or understand it very well, and I think it's accurate to say that a common mistake made by Rails programmers is to misapply Rails-style conventions in other projects.

Rails programmers do have a reputation, in some places, of not being good programmers. (Whether the reputation is entirely accurate is another issue.) I think the most common specific complaint I've heard is that Rails devs don't know SQL because ActiveRecord does it for them.


Thanks for the insight.

I guess what I was really getting at is the folks who know Rails, but not Ruby. If you don't know the language underlying your own framework, it seems unlikely that you'll know much else, language-wise (like C, for instance). I'd be loathe to call someone who doesn't really know any programming language a programmer at all.

It almost seems like the arrogance alluded to by many posters in this thread comes from using a framework that is itself perhaps a work of genius, as if that somehow implies that merely using it is genius, too.

The other thing that surprised me in that post was "the barrier to entry with learning rails is a little tricky". In the context of all the flak that the "Java schools" (which seems to be all of them, now) get for not weeding out weak programmers, I would have guessed that learning Rails would be even easier. Comparison to PHP doesn't seem like a very good yardstick for aptitude.


I think there are two types of claims typically made in the "people who use X are better/worse programmers than people who don't" argument.

One is a claim based on difficulty. X is really hard, so if you can use it successfully, you must be an excellent programmer.

Another is a claim based on taste. You must be very sophisticated and knowledgeable in order to see why X is good, so people who choose X are excellent programmers, because they know the difference between good and bad technologies.

I tend to feel that you shouldn't take credit for having good taste in frameworks (or text editors, or etc.) until you have worked with more than one. Otherwise, even if you pick the 'best' one right off the bat, it was mostly luck.


Yes I find it odd that someone would limit their own description not just to a single programming language, but a language-framework combination. I much prefer to employ handymen who know how to use both a hammer and a screwdriver, if not all the tools they need.


If you're dealing with a complex system that needs a lot of work, I would recommend trying to break it down into subsystems and handle the subsystems one at a time.

The original article does assume that you're dealing with a system that more-or-less works. If your application flatly doesn't do the right thing, than a big rewrite from scratch may really be the best choice - there's nothing to save.

But spaghetti code doesn't just fall from the sky, it occurs because of politics, stubbornness, and bad processes. Over the course of the 10+ years it took to make the code base, is it really the case that nobody but you noticed the problem? It's more likely that there's a lot of pressure going in the opposite direction, and other maintainers didn't know what to do either.

Dealing with subsystems helps you handle both problems. Management might not be willing to let you rewrite the whole thing, but if you said, "Let's just fix the boot-up process for the Cyclotron 4000 resource. Nothing else changes, just the Cyclotron boot." you might be able to get permission. In a badly-maintained project, it's hard to replace all the instances of one service - that's what makes it 'badly-maintained' - but it's still easier than dealing with the whole system in one go. And, of course, instead of 'fixing' the Cyclotron you're actually rewriting it with a new, non-wacko Cyclotron service.

Then you go back to your manager and say, "It was rough, but the Cyclotron 4000 no longer blocks the start-up. Let's get the next thing on the list." Not only do you have a slightly better project, you also have better credibility with management, which makes it more likely you'll be listened to when you say a certain technical measure is necessary. Next, fix the subsystem that talks to the Cyclotron - and so on. Pick a right time to introduce tests, code review, and all the rest.

Remember that just as you had the experience working with the terrible code base, your managers had the experience of working with the previous 3 or 4 software architects who "had their own vision" and delivered a product that doesn't start up reliably - I don't think it's surprising that there was no longer the political will to assign people to refactoring or rewriting tasks. Bad architecture uses up the political will needed to approve good architecture, because it makes all "architecture" tasks look bad. You need to regard you reputation as a finite, under-supplied resource just as much as your time and budget and plan to get more.

From your use of the past tense, it looks like you're no longer in that situation (good for you!)... but that would be my advice if you see a similar situation in the future. I've used this plan in my own career to rewrite a (much smaller, only moderately troubled) project piece by piece over the course of a year.


Good response! Another part of the problem was that the company preferred contractors over full time staff. It had very high turn over because of this. Many have already replaced subsystems with their own versions over time. There had already been many implementations of the Cyclotron subsystem :). To be honest I probably ended up being one of them. Working there was too stressful and the rewards for trying to achieve more were not recognised.

The place had a reputation for hiring highly motivated engineers and burning them out. Just to be replaced by another. When I left, they hired a very talented guy that I worked with for a couple of months. He left recently and the cycle begins again!


There have been attempts to organize this, including one I know off the top of my head[1].

There are two problems. One is that an orderly transfer of control requires a certain amount of planning and coordination, which are precisely the resources that aren't available when a maintainer has left (or is on the way out). The other is that people tend to become maintainers of other peoples' projects by climbing the open source 'career ladder' from user to minor contributor to major contributor; projects are stable when they have enough contributors that the most-productive non-maintainer can be promoted to maintainer status when the original author leaves.

GitHub helps by making it easy and obvious to fork something and eventually have your repo promoted to be the 'official' one, but as with many problems in open source, finding a particular, specific person who actually does that is the hard part.

[1]http://thechangelog.com/post/1986814704/stillmaintained


Ironically, http://stillmaintained.com is closing down.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: