Enable Pages access control - <AUTHOR> https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/5576 <comment><USER3> Gitlab is amazing in my personal opinion... The autodevops (with connect k8s) has made my life easier by 10x atleast

</comment><comment> white-moss Awesome. Advantage has been added. GitLab is better than GitHub, I think.

<comment><USER4> Try discovering a project/package on GitLab vs GitHub. They really need to add proper search / explore mechanism.

<comment><USER5> I'm ok with a git hosting platform that has absolutely zero social media elements to it.

<comment><USER6> This also affects self hosted instances in a company where you want to find other packages though. It's not a "social network" feature.

<comment><USER7> You're telling me there are cases where a company has so many projects in it's gitlab instance that employees routinely have to _search_ for things? That seems odd to me. I'd expect there to be a naming scheme for most things, and even if there's some oddball project, I'd think somebody else you work with knows about it and where it is. My company has maybe 20-30 projects, and I can find any of them easily if I know the client's name.

<comment><USER6> > My company has maybe 20-30 projects

Ever worked in a company with micro services or a company that has a bunch of employees? You'll have hundreds of projects easily if it's a bunch of teams. If someone tells me "it's in our SRE libs package" I'll go ahead and search that. (Usually I can't find it because it's in a separate namespace on our Gitlab instance. Doing that is an Enterprise only feature on Gitlab right now: [https://docs.gitlab.com/ee/user/search/advanced_global_searc...](https://docs.gitlab.com/ee/user/search/advanced_global_search.html))

The point is that search is important and not a social network gimmick.

<comment><USER7> I hadn't considered companies that use microservices instead of monoliths, I think you might be right

<comment><USER8> Yep, same here. We architected our services so that a common layer could be used which reduces service duplication but still we have over 700 projects for just one company doing end-to-end ecommerce and fulfillment. At some point you even start running out of names so you end up with people using acronyms from their specific fields which quickly ends up being unfindable. Not because of search but because you no longer know what to search for.

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER9> Very excited about hosting code coverage reports (with line by line coverage) for developers.

</comment><comment><USER10> All that's missing is the ability to control these settings through the API - same with Letsencrypt certs / auto ssl.

</comment><comment><USER11> Can someone explain to me what this does? It seems to me that it restricts Pages to project members, but I've had that feature enabled on private repos for at least a week or two now, which makes me think this is something different, but I can't figure out what.

<comment><USER12> That's what it does. It's not that new, it's been live since Sept 27 ([https://gitlab.com/gitlab-com/gl- infra/infrastructure/issues...](https://gitlab.com/gitlab-com/gl- infra/infrastructure/issues/5576#note_222976738)).

<comment><USER11> Ah, okay, that makes sense, thanks! I can't tell you how much trouble I've had deploying docs with authentication to an org that uses GitHub, I basically spent a whole day figuring something out and gave up. GitLab was literally one setting.

</comment></comment></comment><comment><USER13> It's nice to know other orgs also have these checklists where lots of items aren't checked, and you have no idea if they _should_ be checked, or when, why, etc. Does anyone have a good solution to this?

</comment><comment><USER14> I really like their checklist. It brought many details to my attention that I would have missed when developing such a feature. Does anyone know such a list of checklist (awesome-checklists or so)?

</comment><comment><USER12> I love GitLab, and Pages access control is a great feature, but I think this was rolled out very poorly.

<rant>

The access level is "Only Project Members" by default for private projects, which I consider a breaking change because the steps I previously used to create public Pages (add .gitlab-ci.yml and push) no longer work.

The first time I tried to deploy Pages after the access control feature was enabled I wasted a lot of time because of this. When my new webpage redirect to the GitLab sign in page, I didn't bother signing in (why should I, when Pages have always been public?). I waited a day, because Pages have taken several hours to provision in the past[1]. Finally I started searching the web for why Pages was redirecting to the sign in page and found out about the access control feature.

I support having the access level "Only Project Members" by default, but I think the rollout could have been done much better. My main objections:

\- There was no indication that the new webpage existed and that the issue was access control -- when I tried visiting the webpage for a non-existent project I got the same redirect. I understand why (to avoid leaking the names of private projects), but the redirected sign in page could have still shown a generic message ("project is missing or private") and mentioned that Pages are now private by default.

\- The setting was not in an obvious location for me. I checked "Settings > Pages", which said the pages are served but did not give any indication that access control was enabled. There should have been a notice here saying that Pages are now private by default and that this can be changed in "Settings > General > Permissions", at least for the first few months after the rollout.

\- The API [2] does not support changing the Pages access level yet, so I have to sign in to GitLab and change it manually (or fake the form submission). I want to be able to create a project with public Pages from the terminal, like I could before.

These issues could have stemmed from an assumption that developers heavily use the GitLab web interface and are always signed in. For me that is not the case.

Some small additional issues:

\- The option "Pages access control" in Settings > General > Permissions is badly named because it's not clear what it means when it's toggled off. With the other options (e.g. "Issues", "Wiki", "Snippets") it's clear that toggling off the option removes the feature, but toggling off "Pages access control" could either mean "remove the access control feature" (making the pages available to everyone) or "remove the Pages feature" (making the pages available to no one). From my experiments it appears to be the second.

\- The options have a glitch where toggling an option puts the corresponding access level in an inconsistent state. When the "Page access control" option of a private project is toggled off then on, the access level dropdown shows "Only Project Members" as selected but the value of the hidden <input> element is 30 (Everyone). Submitting the form sets the access level to "Everyone", as can be seen when the page refreshes. The other options have the same problem.

</rant>

[1] [https://forum.gitlab.com/t/gitlab-pages-404-for-even-the- sim...](https://forum.gitlab.com/t/gitlab-pages-404-for-even-the-simplest- setup/5870/58)

[2] [https://docs.gitlab.com/ee/api/projects.html#edit- project](https://docs.gitlab.com/ee/api/projects.html#edit-project)

<comment><USER15> Thanks for the list. I've shared this with the group responsible for pages.

</comment></comment><comment><USER16> Gitlab has enabled China's censorship of foreign content and free speech:

[https://www.theregister.co.uk/2019/10/16/gitlab_employees_ga...](https://www.theregister.co.uk/2019/10/16/gitlab_employees_gagged/)

<comment><USER17> It's non of GitLabs business to play the judge in this. If a customer is doing something illegal and a court makes a judgment, they will probably do something.

I prefer a company not ruling their platform by their beliefs but by their countries laws and court rulings.

<comment><USER18> That sounds like a great idea but quickly gets you into very murky Waters, especially wrt China.

If the government in question doesn't try to be just, you'll end up assisting murder and silencing the voices of the oppressed.

Sometimes it really is better to say "no" to a business opportunity, if the other side isn't behaving in a sane manner.

And fwiw: gitlab did just that as the sister comment pointed out

<comment><USER19> I think this is more nuanced. Right now companies cooperation with China is in the news. For example, both Blizzard and the NBA have betrayed American ideals in favor of making money in China. Other companies have built a dependent relationship with China over many years, and have been forced through this dependence to support China (Apple comes to mind here). Other companies are actively distancing themselves from politics (gitlab).

As a society, I think we need to decide what is best. In my opinion, companies should be entirely apolitical, both internationally and domestically. Further companies should not assert any influence _at all_ over political speech by their employees. In return, employees should not imply corporate support for a particular political view.

From my perspective, gitlab is doing the right thing. I don't think corporations have _any right_ to involve themselves in politics, even if the majority supports that position.

Edit: if popular sentiment is that American corporations shouldn't have a dependent relationship with China, then the _elected_ government should enforce sanctions. I don't need corporations enforcing moral policy.

<comment><USER20> Please keep in mind that "apoliticism" is in itself a political position: wanting to preserve the status quo and opposing change is still support for the status quo which, in itself, is a set of political beliefs.

<comment><USER19> It's not. If corporations were people I would agree, but they aren't. Politics should be democratic. I don't want to live in a corporatocracy.

<comment><USER18> It's impossible to be completely apolitical. Take your own example - <USER2> - and tell me how they could stay moral without taking a political stance.

<comment><USER19> Morality is for people. Companies should just follow the laws of the country they are operating in. If we decide that isn't morally acceptable, then we can 1) stop using their services, and 2) push for change through our political representatives.

I agree that if Blizzard were to respond to the loss of customers by pulling out of the Chinese market, then that would be not entirely apolitical. Still, it is far less political than they are presently.</comment></comment></comment></comment></comment></comment></comment></comment>


How to get Hilary Mason to build your recommender for free - <AUTHOR> http://blog.mortardata.com/post/49934459499/recommender-systems-for-free

<comment><USER2> awesome!</comment>


Slashdot Struggles to Remain Relevant in The Social Web - <AUTHOR> http://www.readwriteweb.com/archives/slashdot_struggles_to_remain_relevant_in_the_socia.php <comment><USER2> Slashdot is a top 1,000 website, it has only grown in audience over the years, I fail to see how it is 'struggling to remain relevant' in this sense.

Sure it has its problems, the audience has changed significantly over time, they've added stuff (idle??) that literally drove out a good portion of the old guard but it's a little premature to describe them as struggling in terms of remaining relevant.

HN contains plenty of refugees from /. so I'm sure that to many people here this will be a recognisable subject but for every person that left 10 more joined up in the meantime.

Relevance is hard to measure anyway, a few anecdotes and the woopra stats are not going to convince me that the 100's of thousands of visitors per day that slashdot attracts are no longer a force to be reckoned with.

Personally I find the woopra stats more than a little bit suspect _because_ /. shows up as a 0, I find it hard if not impossible to believe that sites much smaller than /. in audience size result in an overall infinitely larger number of visitors.

A '0' in a result like this is suspect. Maybe they forgot to include .org domains ;) ? Probably the result says more about woopra and the sites they analyse or their methods than it does about slashdot.

</comment><comment><USER3> I still read slashdot. I think the problem with it is that stories are sometimes slow to hit the front page. It's not uncommon to have day old news as the top entry on slashdot.

I'm really not sure what facebook integration has to do with anything, I doubt that slashdot users left because of that.</comment>


People who eat only meat to become more healthy - <AUTHOR> https://www.youtube.com/watch?v=Yj_Bc9hdHa0 <comment><AUTHOR> Also done by Jordan Peterson "Jordan Peterson - The Carnivore Diet Changed My Life! - Joe Rogan Podcast" [https://www.youtube.com/watch?v=KGikB-54Lwk](https://www.youtube.com/watch?v=KGikB-54Lwk)</comment>


Group of 17 Apple Auto Engineers Join Startup Zoox - <AUTHOR> https://www.bloomberg.com/news/articles/2017-08-30/group-of-17-apple-auto-engineers-is-said-to-join-startup-zoox <comment><USER2> This gave me the impression that 17 engineers left all at once in a coordinated way, but after reading the article I'm still not sure. Over what period of time did the 17 engineers leave? If they all coordinated and left at the same time that's quite a statement.

<comment><USER3> That's not quite as interesting to me as the fact that no one has cracked this nut yet. No one. You've got the top tech companies on the planet trying to be first and as of yet not one of them has managed it. I thought Apple would be first or a close second with a better and more refined solution. But they have supposedly given up on the larger picture and are focusing on the software.

If I was an engineer this is clearly where I would seek to work, this is obviously one of the harder tech problems to solve.

<comment><USER4> You're spot on. Autonomous driving (level 4/5) has been demo'ed by a few players at low speeds, but no-one has a product to market yet. While Google/Waymo currently seems to be farthest, it will take 10 years for clear winners to emerge.

One of Zoox advantages (compared to Apple) is that as a pure play autonomous driving company they can retain focus over long time scales. The Apple project seems to have changed focus multiple times.

</comment></comment></comment><comment><USER5> Would be hilarious if Uber bought them and Apple sued Uber.

</comment><comment><USER6> Zoox got some Uber engineers too since earlier.

I wonder if the company will produce a working product or if they will aim on getting bought, like Otto etc.</comment>


Please do not attempt to simplify this code - <AUTHOR> https://github.com/kubernetes/kubernetes/blob/ec2e767e59395376fa191d7c56a74f53936b7653/pkg/controller/volume/persistentvolume/pv_controller.go <comment><USER3> I love this! It's the "jazz music" of software development. Something which breaks all the "rules" but does so purposefully and explicitly so that it can become better than the "rules" allow.

A naive look at this and my head is screaming that this file is way too big, has way too many branches and nested if statements, has a lot of "pointless comments" that just describe what the line or few lines around it is doing, and has a lot of "logic" in the comments which could quickly become outdated or wrong compared to the actual code.

Yet at the same time, it's probably a hell of a lot easier to maintain and manage than splitting the logic up among tens or hundreds of files, it contains a lot of the inherently complex work it's doing to this file, and it is so well and heavily commented that it should be pretty easy to ensure that any changes also keep the comments up to date (after all, any change without changing the resulting comments should show up like a sore thumb, and will most likely prompt the reviewer to look into it at the very least).

<comment><USER4> > probably a hell of a lot easier to maintain and manage than splitting the > logic up among tens or hundreds of files

I'm only halfway through John Ousterhout's book Philosophy of Software Design but I think it agrees with you on this -- that smallness-of-file or smallness- of-function is not a target to shoot for because it prevents the things you build from being deep. That you should strive to build modules which have deep functionality and small interfaces and should contain their complexity within them so the users don't have to know that complexity.

<comment><USER5> I just finished his book yesterday; he has a lot to say about size and comments. For size, your summary is spot-on. I'd only add that he notes overeager splitting of methods and classes makes code involved in a particular abstraction to be no longer in one place, leading developers to constantly jump around files, which makes it more difficult to understand the code and increases the chances of making bugs.

As for comments, this file is essentially Ousterhout taken to the extreme. Still, I think he would have like it, given how critical this file is. In the book, he encourages writing more comments than the current trends would suggest, pointing out that you can't fully express abstractions in code, so all the things the code doesn't contain - the high-level concepts, the rationale, the caveats - should be documented in comments in appropriate places.

Overall, I'm extremely impressed by the book, and its focus on reducing and mitigating complexity.

<comment><USER6> Martin Fowler of the Agile world, and Garret Smith of the Erlang community, are both excellent programmers whom I respect, and they both take the approach of breaking code into lots of extremely small functions.

Having tried that style, I notice that I don't particularly favor it, and for the very reason you site: the code is no longer all in one place.

I've switched to moderately sized methods/functions with comments every few lines. Some say that comments like this are a smell, and that you should refactor the commented section of code into it's own function, but honestly comments are easier to read than method names (and again, there's the benefit of locality).

I'll have to take a look at the book.

<comment><USER7> I assume everyone who splits code into smaller pieces use modern IDEs that makes it trivial to navigate to functions by clicking them etc.

I say this because I'm always astonished by the number of "modern" programmers who refuse to use IDEs.

<comment><USER5> > _I assume everyone who splits code into smaller pieces use modern IDEs that > makes it trivial to navigate to functions by clicking them etc._

That's... not the point. Jumping around is. Imagine reading this comment thread on a bizarro-HN, where you only get to see a short camelCased summary like: debunk(this.previousComment), and have to click to open each comment in a new tab. This is how jumping around small functions feel.

> _I say this because I 'm always astonished by the number of "modern" > programmers who refuse to use IDEs._

There are reasons for it. Many languages don't have an IDE. Many are not suitable for one (especially ones closer to Lisp on expressiveness spectrum). IDEs are heavy and often mouse-oriented, and not efficient for reading and editing text. Sometimes (read: Java) they are a crutch to work around the expressive deficiencies of the language.

Mind you, I have nothing but good things to say about IntelliJ. I've spent a lot of time in it even recently, and I pick it up any time I have to do anything in Java. But for everything else, I launch Emacs, because it can handle all other languages well, and has superior editing capabilities.

<comment><USER8> > That's... not the point. Jumping around is.

There is a tradeoff: Small functions make high-level logic clearly visible and easy to find, at the price of forcing you to jump around when you want to dive into implementation details. Putting everything into one big function lets you follow all the implementation details without jumping, at the price of making you read everything to actually _understand what the code is doing_.

The latter is the biggest price you can possibly make me pay. Jumping around is a minor inconvenience.

<comment><USER9> By choosing the right names for a function or class a lot of jumping around can be prevented. Most IDEs also have a feature (including key combination) to show the documentation of the method/function. The only reason that remains is when you doubt the correctness of the method and need to look at its definition.

<comment><USER10> The only and _critical_ reason - skipping the check will net you tons of debugging all the time because hidden assumptions are often not documented. (or otherwise visible)

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER11> Ignoring the initial boilerplate (license, imports) and the request to preserve the verbose ("space shuttle") style, the first line is:

        // Design:
        //
        // [... 4 paragraphs of English prose
        //      explaining goals and intent... ]

That's _exactly_ the type of comment that should be at the beginning of most files!

<comment><USER12> As a novice programmer, I was absolutely stunned that this was not standard practice. A typical source file provides zero context, background on the subject, pointers to reference material/blog posts/books explaining the concepts, information on how it fits into the program's 'bigger picture', or (most importantly) the thought process that resulted in the file (i.e., why the choice was made to do _this_ rather than _that_, challenges faced, trade- offs, etc.).

It still baffles me. Every programmer has to start from scratch dealing with a new codebase, and it makes improving any non-trivial program impossible unless one is willing to spend hours of archaeological examination. To open-source developers: if you want to get people contributing to a project (and make everyone's effort much more enjoyable!), these sorts of comments are essential. Not to mention they'll save everyone boatloads of time; it's a shame that every programmer has to piece together knowledge from scratch, rather than being 'tutored' by their peers' comments.

<comment><USER13> There's plenty of good reasons to not write 95% of code with big walls of explanation. The first is a matter of cost: Writing a good explanation around everything is very expensive to do at first. A whole lot of the custom code you find in random companies, from the shiny SV startup to the old enterprise, is unimportant, cobbled together pieces. We have no idea of whether we are writing code that will be thrown away in a week, a month, a year or whether it will last two decades. Context can change fast enough that the comments become worse than useless, as the terminology might have changed, or had been misguided in the first place, turning the long comments into outright unintended deception. This gets even worse as we do not evaluate all the comments in all the files whenever there's a code change: It's crazy how a large comment block in one place can become harmful after it's forgotten, and someone else makes a correct, business critical change in another file. No matter where I am working, it's rare for me to not find multiple examples every year where the code and the comments provide very different impressions of what is going on, and it's the code that is accurate.

This is not to say that there aren't reasons to write large comment blocks, or architecture documents, but that they are often better written not while the system is being first built, but later, in a maintenance cycle, when someone already had wished for the comments, and has regained the knowledge the hard way. By then, it's clear which part of the system are dangerous, suspicious and unclear. Where there's more need for high quality error handling, and where thousands of lines of error handling never get hit, because the failing case that was originally considered doesn't really happen in this dimension anymore.

Writing code so that someone, even a future you, can pick it back up and improve it when it's needed, while still delivering the code at a good pace is a kind of skill that many just don't learn, either because they are always in greenfield teams that never pay for their mistakes, or have an approach to maintenance that involves not becoming intimate familiar with a system, and instead either hack or rewrite.

But nobody looks great in a resume by saying that they are a specialist in software maintenance.

<comment><USER5> > _This is not to say that there aren 't reasons to write large comment > blocks, or architecture documents, but that they are often better written > not while the system is being first built, but later, in a maintenance > cycle, when someone already had wished for the comments, and has regained > the knowledge the hard way._

I don't think the "Lean Manufacturing" approach works here. By the time someone "pulls" you for a comment, you've already lost the most important knowledge that should go into the comments - _why_ the code is the way it is. Maybe you'll recall it when asked, hopefully not missing anything crucial. Meanwhile, comments are extremely cheap to write as you're writing the code, and even before you're writing the code (you did spend the time thinking about what you'll write, and aren't just "coding from the hip", right?).

<comment><USER14> Commit logs are also cheap to write, and it's easier for people to realize that whatever you read in "$vcs log" or "$vcs blame" might be severely outdated.

</comment></comment></comment></comment></comment><comment><USER15> Having spent 25+ years writing, viewing, commenting on and reviewing code in a multitude of languages, this is good stuff to see - regardless of the 'style' of programming (or the language broadly-speaking).

Stepping back and whilst we can all overlook it, good code comments can make an enormous difference in productivity - both for an individual, a team and indeed a business. It aids repository knowledge (something that is easily lost between current and prior teams/individuals), which shouldn't be mistaken for the intelligence of someone looking at code...

I've spent far too much time personally and otherwise attempting to reverse- engineer code written by someone with no comments or explanation. At times, super experienced programmers/developers will take performance-enhancing shortcuts that the less-experienced don't understand; They'll compress routines and functions that are a result of their explicit knowledge of a language and/or domain but without explanation...

On a basic level, comments should: inform, educate, outline and help others understand the sometimes complex routines and functions that we all create and often under an enormous amount of pressure.

There are those that believe good code shouldn't need explanation and to _some_ degree that's true, but you can't apply that brush to every codebase. Code can become complex, awkward, spaghetti-like and almost unfathomable at times.

I've always strived to teach less experienced developers to comment well, efficiently and with a little humor/humour (where possible); Something that allows us to understand code quickly, appreciate the efforts of those before us and smile/grin at the complexity of a challenge.

Personally, I don't really care about the code/comment ratio - It's a complete red herring. At times, code comments can be worth more than the code itself. At other times, they just help you get your job done; quickly, efficiently, no fuss, just great code.

<comment><USER16> > There are those that believe good code shouldn't need explanation and to > some degree that's true, but you can't apply that brush to every codebase. > Code can become complex, awkward, spaghetti-like and almost unfathomable at > times.

I have yet to find a codebase that couldn't be made clear as soon as a programmer actually put some effort into doing so. Far too often adding a comment is used as an excuse to give up on making the code readable before you've even started.

<comment><USER17> Here's a great practice:

1\. Write some piece of code

2\. Now write a comment about it

3\. Is the comment adding more information, making the code more clear?

If Yes: Put that information into the code. Rename variables. Pull out code into subroutines.

If No: Delete the comment.

You'll be amazed at how often this practice works. Doing it all the time will make your code more readable.

We have a second, enforced practice at work, thanks to code review. The question in your head is simply: "Am I gonna get a comment about this at review time?" If yes, you gotta make the code clearer/simpler/better. Because you'll have to answer and address the comment, and that's just gonna slow you down more than if you just fix the problem now.

<comment><USER18> There are concerns and aspects of software engineering that are important to document but don't sit well in code, but they become important when reading / maintaining that code. Design decisions (implementation details), specification details, other design or engineering constraints. And of course business modeling fundamentals and constraints.

Sure, in theory, you can do everything in code, but I find that usually this trade off is taken, as there's no time/budget to go that 80% extra time. (Or however the Pareto curve looks for the actual problem. And usually it's not less than 80, but more.)

<comment><USER15> I would never suggest documentation in code alone... Your point is very much noted, echoed and a hat-tip to you here. Yes, documentation is incredibly important, and it should be used as an driver/accompaniment along with comments.

</comment></comment></comment></comment></comment><comment><USER19> "it became clear that we needed to ensure that every single condition was handled and accounted for in the code"

This is a feature of several (mostly functional) programming languages, e.g. Haskell. Fun to see that often people figure out that these types of concepts are a smart way to write your code. Too bad it usually means many people reinvent the wheel instead of learning about computer science history and other languages.

<comment><USER20> I know a business coach who regularly asks his audience "Who here makes better burgers than McDonalds?". When half the audience raises their hand, he asks them why they don't outsell this giant company.

Functional programming advocats, especially for the "pure" ones like Haskell, always strike me as odd. It seems that all the beauty of those languages make people obsess over that beauty and purity while keeping them from being productive.

Meanwhile, people with simpler languages like Go just get stuff done that is useful and makes people happy. Now if I _ever_ came across a useful Haskell product, I'd be happy to test drive it, shouldn't be a problem by now with all the container technology. But the closest I ever came to using a functionally developed product was RabbitMQ (written in Erlang). That one was _such_ a pain to use and operate — must have been the developers still dreaming in the purity of its code instead of writing some installation docs. I moved on to Kafka later and didn't regret it a minute.

Rant off.

<comment><USER21> Selling a lot of burgers encompasses much more than making good burgers. By the same token, good products entails much more than making a programming language choice.

Functional programming, at its heart, is about using self-imposed constraints to avoid certain classes of programming mistakes.

If your application domain doesn't have big consequences for these classes of programming mistakes, then it can seem like functional purity can be a luxury or frivolous. However, if your application domain suffers greatly from those classes of programming mistakes, such as distributed systems, then it may be worth it to consider what functional programming might buy you.

So yes, just because you use a functional programming language won't help you sell your widgets or make a great product. And you can spend lots of time fucking around with it for its own sake and still not sell widgets or make a great product. However, if you understand what its constraints buys you, then you can make your job of building these things in certain domains much easier.

<comment><USER22> > So yes, just because you use a functional programming language won't help > you sell your widgets or make a great product. And you can spend lots of > time fucking around with it for its own sake and still not sell widgets or > make a great product.

It comes down to trust. You're either fucking with your code in a powerful programming language that lets you do everything, or your fucking with the language restrictions to get your code to compile in the first place.

You can either go eat at McD's which sells pre-cooked burgers from minimum wage employees which kills the flavor and the taste of the meat being served but is extremely safe, or you can go to an upscale burger joint where artisans grind their meat in house and cook it to a perfect medium rare.

These days, I prefer the latter.

<comment><USER23> > It comes down to trust. You're either fucking with your code in a powerful > programming language that lets you do everything, or your fucking with the > language restrictions to get your code to compile in the first place.

> ...or your fucking with the language restrictions to get your code to > compile in the first place

I think that's a wrong and outdated view on strong type systems.

A good type system is also an ergonomic one. What people start to experience is that the compiler is actually a friend that helps you write code and keep yourself true to your own promises. When new people start Elm, PureScript or Haskell (or another lang with ADTs and Type Inference), they might be a bit overwhelmed with the paradigm shift, if coming elsewhere, but if you are new to programming, there's nothing inherently more difficult in Haskell than in other languages—the cost of wrong code is just apparent earlier.

It doesn't come down to trust, it comes down to the realization that your mind can keep track of less information than a computer, and that you, as a programmer, are forgetful and make mistakes. The compiler is there to help you when you stumble over your own feet.

NOTE: I'm only including strongly, statically typed languages with type inference in the above. "FP langs" by itself is far too broad to be a useful categorization.

<comment><USER24> Even experiences FP folks complain about how difficult it is to program in Haskell due to its purity. Further, the high barrier to entry you describe is an even bigger deal to organizations than to individuals. It's a cost that needs to be paid for every employee. And it's not just the language features, but FP languages tend to have issues like poor documentation, poor editor integrations, multiple standard libraries, multiple build tools, multiple string types, home-grown project file syntax, multiple preludes, many extensions, etc. All of these boost the learning curve in addition to the issues with the language itself.

<comment><USER25> In my limited experience with functional programming, I've come away with the impression that the problems you're describing are why you don't see a lot of companies that use FP exclusively.

But I think the advantages that OP is lauding are also there, and "space shuttle code" might just be where it shines. Reading that comment in this post made me immediately think of Haskell. The Clojure components at my company fits the "space shuttle" description of importance, and its dependability is striking compared to the rest of our code. Part of it may be that being written in a different language allows its concerns to be separate from the rest of the application too, but I do think the FP paradigm is simply good in this domain.

<comment><USER24> Sure, but I doubt all of Kubernetes is written in this style, so it's probably not worth writing everything in Haskell. Note also that there's nothing about FP that prohibits it from addressing the aforementioned practical problems. Some Haskell-like could swoop in and totally steal Go's lunch if they would simply prioritize practicality over experimentation.

<comment><USER22> > Some Haskell-like could swoop in and totally steal Go's lunch if they would > simply prioritize practicality over experimentation.

I don't know. It seems like it would be easy enough to build an AST to make sure there were no unknown conditions that didn't lead to a return statement.

<comment><USER24> I don't understand how your post relates to mine. I was saying that if a static functional language focused more on simplicity, readability, good tooling and documentation, etc then it would eat Go's lunch _without trading off any of Haskell's important characteristics_ (I.e., robust type safety).

</comment></comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER26> My take away from reading this code is that it is a huge mess that may be impossible to clean up. At some point they failed to introduce abstractions that would remove the need for all this complexity. They are probably right that now that it works that it will be hard to refactor it without leaving out some critical case. However, I pity anyone that works on this code base.

<comment><USER27> Abstractions don't remove complexity. Abstractions instead hide the appearance of complexity behind layers of ever increasing code.

<comment><USER28> I believe that premature abstraction is terrible. But in some cases good abstractions may help with handling complexity and may make testing easier. I have a feeling that because authors say that this class should not be changed / refactored, they failed to introduce a good abstraction. This also implies that their tests are inadequate.

<comment><USER27> I agree with the direction of your opinion, but would say it isn't a matter of helpfulness. In some cases is it is a necessity.

It must be understood that complexity is an economic consideration and not either a financial or technology consideration. It is always already present. Complexity is not something that is created or destroy; but retained, absorbed, or transferred.

Abstractions become necessary when they separate different functional layers to perform different respective responsibilities. In this case complexity is transferred both in and out of a system at a given layer, but you don't care so long as you aren't doing the jobs of the other layers. That is referred to as separation of concerns which results in the hardening of a system (risk reduction) which is the side effect of reducing costs due to restricting requirements available.

Many abstractions exist solely to provide a layer of convenience. In the case where an abstraction does the same job as the code it abstracts risks increase and costs increase. This is because the system continues to simultaneously absorb and transfer complexity like described above, but the requirements between the various layers isn't clearly separated. That results in fulfilling requirements, the same requirements, simultaneously at various layers. This has various names like _scope creep_ , _technical debt_ , and so forth. This is bad because risks and costs increase directly to the correlation of increased code and increased requirements. This is what makes the _law of leaky abstractions_ valid.

It is easy to tell the difference between a necessary abstraction and a wasteful abstraction by the forcefulness of separation. If you can perform the same job in a lower level the abstraction isn't necessary and you are probably better off without it. Most JavaScript frameworks are unnecessary abstractions.

</comment></comment></comment></comment><comment><USER29> As much as I like the style where the code logic is commented very thoroughly, it also falls in the trap of comments no longer matching the current code, I assume some variable renaming happened. In the function (line 320 of [https://github.com/kubernetes/kubernetes/blob/ec2e767e593953...](https://github.com/kubernetes/kubernetes/blob/ec2e767e59395376fa191d7c56a74f53936b7653/pkg/controller/volume/persistentvolume/pv_controller.go))

       func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVolumeClaim) error {

the variable "pvc" seems to have been renamed into "claim" and "pv" into "volume", judging from the code/comment mismatch. Comments in the lines 339, 358, 360, 370, 380, 395, 411, 422, 427 point to the old names. Furthermore in line 370 the comment reads:

       } else /* pvc.Spec.VolumeName != nil */ {

while the matching if is:

      if claim.Spec.VolumeName == "" {

So not only the variable name mismatches, but also the comment is wrong. The VolumeName seems to be a string, so is never nil, the else comment should specify that the VolumeName is non-empty.

The more verbose and detailled the comments are - the more work needs to be spent in ensuring that they are correct.

<comment><USER30> Yes and that actually PROVES why this ultra-commenting mentality is crazy.

</comment></comment><comment><USER31> > Space shuttle style is meant to ensure that every branch and condition is > considered and accounted for…

FTFY: …hopefully!

Only if they've used a language with Algebraic Data Types support, the compiler would enforce that "every branch and condition is considered and accounted for." The only PL with ADT that I've used was Haskell, but I've heard that Rust has them too "enums".

People are arguing that "code is what computer executes, comments don't ensure anything!" and so on, but besides being executed, (this Go) code does not ensure anything either. It's human eyes that skim through all the cases, and look for a matching branch for every one of them that "ensures."

In my humble opinion, this so-called "space shuttle style" is just one of the many workarounds to deal with Go's by-design limitations (the most famous one being lack of generics), a language that's designed only 9 years ago.

<comment><USER8> > It's human eyes that skim through all the cases, and look for a matching > branch for every one of them that "ensures."

This a thousand times. The praise in this thread is disturbing.

The absurdity of this code is the logical conclusion of ignoring decades of PL advances in favor of Go's "simplicity."

When you insist on "space shuttle" era language design, is it any surprise when you're reduced to "space shuttle" era programming? I can't imagine anything more fitting.

<comment><USER32> You are forgetting the tremendous advantages that Go offers for many projects over alternative languages.

There are no perfect languages, that is certain.

</comment></comment></comment><comment><USER33> I see a lot of comments mentioning various versions of the following:

\- "It's the "jazz music" of software development."

\- "...breaks all the "rules" but does so purposefully..."

\- "this is irreducibly complex, and cannot be split into multiple files"

\- "that smallness-of-file or smallness-of-function is not a target to shoot for"

I am wondering: can't all the above statements be said in defence of _any_ poorly engineered, gargantuan single page code?

<comment><USER34> Can everyone play jazz?

No.

<comment><USER35> Can everyone claim that their terrible music is jazz music?

Yes.

<comment><USER34> Apart from a comedy bit, can everyone easily spot the difference?

Yes.

<comment><USER36> No. Most jazz, including by the jazz greats, just sounds plain terrible. The worst is jam sessions, where everyone steps over each other but it sounds not abysmal at times because they're in the same key.

</comment></comment></comment></comment></comment><comment><USER37> This code reminds me of why ML-like languages with Maybe-style types and case expressions that generate compiler errors for missed alternatives are good. I bet rewriting this in OCaml or Haskell would lead to tighter code and might even unearth a couple possible states that haven't been accounted for.

<comment><USER38> You don't really need functional languages to have those features, as swift, kotlin and others show.

<comment><USER16> Those languages have all of the ML features; they are functional languages in every reasonable sense, unless you consider "functional" to mean the absence of something.

</comment></comment></comment><comment><USER39> If you want to see actual code that flew to the Moon: [https://github.com/chrislgarry/Apollo-11](https://github.com/chrislgarry/Apollo-11)

<comment><USER40> My favorite part from that: [https://github.com/chrislgarry/Apollo-11/blob/27e2acf88a6345...](https://github.com/chrislgarry/Apollo-11/blob/27e2acf88a6345e2b1064c8b006a154363937050/Luminary099/LUNAR_LANDING_GUIDANCE_EQUATIONS.agc#L179)

<comment><USER41> I also like the "trashy little subroutines" comment.

</comment></comment></comment><comment><USER42> This is basically the style that rust sort of forces you to write in with allowing shorter forms where the compiler can automate checking that all error states are accounted for.

<comment><USER43> And with the beauty of pattern matching in Rust, it's usually very painless.

</comment></comment><comment><USER44> The comment:code ratio is higher than anything I write or that I've seen.

However, it does give me some comfort. When it's not gamed, do other HNers also feel that a high comment:code ratio probably indicates quality?

There are reasons why this may be the case. (More thought, more time and a large team etc)

I don't advocate using this measure to reward anyone because it would be gamed immediately.

<comment><USER45> I actually would say it's almost the opposite, if you're writing clean, expressive code it shouldn't need explaining.

And if your code is clean, you shouldn't have a bunch of redundant comments explaining the obvious.

<comment><USER46> I'm not sure there are many cases where there should be _long_ amounts of expressive code.

If you're doing something obvious, you should generally be able to program it concisely, in which case you have a high comment-to-code ratio because the amount of code is low. Sometimes this will be because you're importing an external library to do something, or because you're calling out to an internal library. Sometimes this will be because you found a straightforward implementation. If you're finding yourself writing hundreds of lines of code to do a _single_ obvious task then chances are high you're implementing it poorly (and, specifically, in a way where your defect rate is likely proportional to the number of lines of code).

And if you're doing several obvious things, then the point of the code is not to explain what the code is doing, but _why_ it's doing that. What is the business purpose of the code? Which customer cares about this edge case that you're handling, and under what circumstances can you stop handling it? Why did you decide that the common library wouldn't actually work here? If you're converting data from an awful legacy format, why are your ingesters / parsers for the legacy format designed in this way? If you're micro-optimizing for performance, why are the optimizations sound (i.e., why do they accomplish the same thing as the unoptimized version), how do they work, and why did you decide these spots need to be optimized? Each individual thing you do might be obvious on its own, but the arrangement of the whole thing needs comments for each step, which again gives you a high comment-to-code ratio.

<comment><USER45> I might have misused the word expressive, I don't mean bloated code with more than necessary logic.

I just meant simple to understand variable, function, and class names. That combined with small classes and functions, makes following the logic of your program extremely easy.

Following concepts like DRY (don't repeat yourself) and the single responsibility principle ensure that you're making more easily testable code, and I'm sure less overall LOC.

</comment></comment></comment></comment><comment><USER47> One simplification that might be tempting is to replace the "if !condition" with "if condition".

For example, line 463 shows:

      if !found {
        // handle missing
      } else {
        // handle found
      }

I would simplify this to:

      if found {
        // handle found
      } else {
        // handle not found
      }

Or even:

      if missing {
        // handle missing
      } else {
        // handle not missing
      }

The test-negative style is repeated throughout the file, but inconsistently. Sometimes the negative is tested in the if branch, sometimes it's tested in the else branch. Why?

<comment><USER48> My guess is that this is in line with the Go tradition of first handling all the odd cases leaving the essential part of what the function (or block of code in this case) attempts to do as the last part. So "if !found" to me suggests that this is more of an exception than the rule and this is why the code is written so as to deal with it first.

</comment></comment><comment><USER49> Obviously I'm not the intended audience, but I'm not sure it's wise to have CloudVolumeCreatedForClaimNamespaceTag, CloudVolumeCreatedForClaimNameTag, and CloudVolumeCreatedForVolumeNameTag in the same file.

This is almost the worst of both worlds: the trouble of wading through a pile of words, together with the lack of clarity.

<comment><USER50> While I understand your sentiment, I don't think it's a real issue with pretty much any modern IDE.

<comment><USER51> I could imagine quickly scrolling and finding yourself editing code in the wrong function.

</comment></comment></comment><comment><USER52> I can't say I've written overly branchy code, but I have become a fan of leaning on the side of "verbose" regarding comments in code - specifically in nested if statements. So many in the Ops area, "just" writing scripts for themselves ( that the rest of the team starts depending on) will just pound out a script that works, with no notes on its function, design or requirements.

15 months later, they moved to a less stressful team, the app is not functioning because the servers got upgraded, and you wonder how the hell this thing works. And if it doesn't work, you have 60 hours of redevelopment to do.

</comment><comment><USER53> Love this thread. I see this a lot, where engineers blindly follow best practices and have urges to re-factor code when its not necessary. Big files are not necessarily bad and I love that a lot of the comments are with me on this. Having to open several tabs and remembering where you are in the stack can be hard once there are more than a couple of frames / function calls in. There is a lot of benefit to keeping logic in 1 file or 1 function, and there is a time and a place for writing really granular DRY code. As with all engineering, there are always trade-offs to every decision and I think its about time we put to rest some of the traditional rules of thumbs and 'code smells' new engineers learn and adhere to like a bible.

<comment><USER8> > As with all engineering, there are always trade-offs to every decision

This is the cliche that needs to be put to rest.

Yes, often there are tradeoffs. But just as often one thing is better than another thing, and there is no tradeoff.

A worldview in which _everything_ has pros and cons and is ultimately subjective is fertile ground for entrenched habits, because it means never having to admit you're plain wrong, that there is a better way, or that other approaches are simply that much better than yours.

<comment><USER53> I believe code design is ultimately subjective. Unlike other metrics like performance which can be easily and definitively measured, you can't easily measure 'good' code. The definition of 'good' changes based on the context of the code base and function the code is trying to achieve. In this case, choices like having giant functions and files is definitely subjective.

</comment></comment></comment><comment><USER54> The comment claim that every branch is accounted for and yet few functions below you can see this is certainly not the case. They should either have fixed it first and then make such comment or shouldn't make such comment at all. Otherwise this looks a bit cringey.

<comment><USER46> It says "(exception: simple error checks for a client API call)" and that seems accurate to me.

In particular Go (like C) has no built-in exception "throwing" / unwinding support, so for any function call where you want to pass an error onto the caller, you need to do something like

        result, err := try_to_get_a_result()
        if err != nil {
            return nil, err
        }

See also [https://blog.golang.org/error-handling-and- go](https://blog.golang.org/error-handling-and-go) . As far as I can tell, all of the if-statements without else-clauses are doing just this.

(It would be nice in theory if there were better language support for making this lexically obvious but they're in a language where that's not doable.)

<comment><USER54> Is someone not familiar with the code competent enough to decide what is a "simple error check" and not a bug? This is very weak as they suggest that even the branches that would result in no-op are accounted for. So if someone introduce a code with a branch that is unaccounted for that automatically means the code is either faulty or is a "simple error check". With something supposedly trying to be a space shuttle worthy code the lack of definition of "simple error check" is very worrying. Would I want this code to fly me to the moon? I'd be wary.

<comment><USER46> I _think_ you can syntactically state that anything where the check is on the second return value (which is, by convention, the error return) is a "simple error check", and their rule for if statements is always for things that come from a first return value.

For instance, this would not be a simple error check:

        server, err := find_current_server()
        if server != nil {
            ...
        }

because if find_current_server() believes that it's a non-exceptional case that there might be no server at all (i.e., it might return nil, nil instead of nil and an error), then you absolutely want to handle that case.

<comment><USER54> What if the second returned variable is not err, but the code using it assumes it is? (the code breaks the convention) This will not be accounted for. This means with that in mind a lot more discipline must be used to analyse the code that is being used in that module.

<comment><USER46> I think that is highly unusual in Go (but someone who actively uses Go would have to correct me).

Besides, this syntactic rule is not implemented by code but by the author and reviewer, who should know what the function returns. (And shouldn't name it "err", then.) They're doing the best they can in a language without syntactic support for what they want, I think.

</comment></comment></comment></comment></comment></comment><comment><USER55> For background on how actual Space Shuttle flight control software was written I recommend reading the "NASA Manager's Handbook for Software Development". It contains some great guidelines for writing safety-critical software. AFAIK, no Space Shuttle mission ever suffered a serious safety incident due to a software defect.

[https://ntrs.nasa.gov/search.jsp?R=19910006460](https://ntrs.nasa.gov/search.jsp?R=19910006460)

<comment><USER56> Thank you for the link. Could people who have studied it answer whether it is similar to the code here?

</comment></comment><comment><USER57> This looks like an example of why I'm trying to learn more about model driven development these days.

There's probably a lot of wisdom in this file embedded in a lot of noisy Go code. If someone tries to implement this code in a different programming language, a lot of this wisdom would have to be painfully extracted from the Go code. Some sort of extracted decision table format (examples [1]) would be objectively easier to read, could be rendered in different formats, hyperlinked, etc. Maybe a small subsection of this code could be generated from some structured data specification.

Mbeddr [2] is an example of a language that allows embedding decision tables directly in C99. It can also embed state machines and other goodies directly into the code. This is just one way to go... I'm sure some ppl would complain about lock-in in a specific IDE.

It is not clear to me exactly which domain driven techniques could be applied to this particular piece of Go code, but it could be worth it _to find that out_.

From what I see out there model driven design seems to be applied to areas were really convoluted, and some times nonsensical logic needs to be mapped to code, like in insurance policy management, and stuff like that, or for other complicated code like firmware, drivers, protocols, etc. Why can't we apply these techniques to general programming problems?

1: [https://medium.com/@markusvoelter/the-evolution-of- decision-...](https://medium.com/@markusvoelter/the-evolution-of-decision- tables-80ce77bf984c)

2: [http://mbeddr.com/index.html](http://mbeddr.com/index.html)

</comment><comment><USER58> Literate programming [0] is frequently re-invented, in various forms, because it is simply the right way to do things- and each iteration of it is almost immediately discarded, because we're all sinful and impatient creatures.

[0] [https://en.wikipedia.org/wiki/Literate_programming](https://en.wikipedia.org/wiki/Literate_programming)

</comment><comment><USER59> A code style with lots of verbose if statements? Go is the perfect language!

More seriously I've done this style unintentionally before in JavaScript for a similar situation with plenty of branching logic. Stuff that easily could have been have the lines but not as easy to verify by hand. I'm happy to see it being formalized for certain scenarios.

</comment><comment><USER60>
        if claim.Spec.VolumeName == "" {
            // ...
        } else /* pvc.Spec.VolumeName != nil */ {

maybe some cleanup actually would be a good thing.

</comment><comment><USER61> HN: this is amazing! Everyone should be writing code like this!

Also HN: c++ and java are awful! They're so verbose and I have to type so much!

<comment><USER62> What if I actually wanted the ability to get a thing going and quickly working within a few lines, while _also_ being able to spell things out as needed when the use case arises? Crazy I know.

</comment></comment><comment><USER63>
        // 1.  Every 'if' statement has a matching 'else' (exception: simple error
        //     checks for a client API call)

Comment rot? The code is filled currently with else-less if statements, not only for error checking.

<comment><USER35> Obviously there are many people on HN that consider that to be a good thing. I personally agree, this is the typical comment got. Only obviously blinded people wouldn't see this.

<comment><USER63> I don't think that anyone here believes that comment rot is a good thing, or that they are particularly "blinded". I just think that the fact that the comments lie is a compelling argument against the prose comment-heavy style used in this file. In this case it was not a big one because it's trivial to determine that the comment is not true, but in general I think that no comment is better than the wrong comment.

I have not cared to read the file much further so I can't comment on whether comment rot is really prevalent.

Actual "space shuttle code" is AFAIK built to satisfy a specification, not to serve as a specification in itself. When you find that the specification is lacking or somehow faulty, you get the people responsible for it to revise it, wait for the new revision and adjust the code to match. The key is that they are two separate processes. Someone responsible for the specification doesn't need to be concerned with the exact details of the implementation, and those responsible for the implementation only need to be concerned with satisfying the specification.

When the specification and implementation is all mixed up as prose and code in the same file you don't get to enjoy the benefits of separating those concerns. Changing the spec is the same process as changing the code, and the order of change is indistinguishable. You can change some code, but then you have to find all the references to the code you changed in the prose and adjust that too. You can change the prose, but then you have to adjust the code accordingly and any prose that assumed that the code worked as before. You'll be relying on tests and reviews (reviewers suffering the same drawbacks as the submitter) to enforce this, which IMO isn't not necessarily a bad thing, but not exactly rigorous enough to give a "space shuttle" stamp.

</comment></comment></comment><comment><USER64> > Space shuttle style is meant to ensure that every branch and condition is > considered and accounted for

I thought this was what you were supposed to do. Not that I do it every time, because I'm lazy, but Zed Shaw used to say every `if` conditional should have a corresponding `else` (which can also take the form of guard clauses). In Ruby, this is really easy to do because every method has to return something, so you build "returning nil or some String" as a concept into your program. There's a whole discussion around whether _that_ is a good idea, but I digress...going through the motions of enumerating every possible condition for a given piece of logic is not a bad exercise, and can result in very robust code at the expense of the code looking a bit more confusing than necessary.

We have a very similarly-written piece of code to this in our eCommerce platform. This code, written in Ruby, is used to calculate prices of discounts with regards to discount compatibility. There's a big warning atop the method stating something like "Please don't decorate/override this unless you ABSOLUTELY need to, the consequences could be very difficult to debug!". Not the easiest piece of code to look at, but it gets the job done in an efficient way without having to rely on C extensions for performance. We were also focused on correctness here, because calculating the wrong discount group could result in zero or even negative order totals, which our clients would _not_ be happy about. So the code is very verbosely written, isn't optimized for legibility, and strictly specifies both if and else sides of each conditional.

</comment><comment><USER65> This kind of pattern indicates that the underlying language has inadequate metaprogramming facilities. You should be able to _robustly_ verify certain guarantees via the type system instead of relying on a specific code formatting convention to do it.

</comment><comment><USER66> DRY is one of the most overly used of the software adages. It more often leads to premature abstraction and overly complex code. My personal preference is explicit code.

</comment><comment> munk-a This style of code with an emphasis on branch completeness is the biggest virtue Go gets from the lack of exceptions.

I personally dislike that style since that level of detail seems extraneous for normal tasks, but when you need to write code with absolute assurances like this then preventing the stack from being unwound without an explicit return (or panic, because some stuff is just terrible) is quite helpful to inspect and insure you have full coverage.

<comment><USER67> Rust's Result or Haskell's Either are wholely better for this purpose.

</comment></comment><comment><USER68> I've already seen a few places where this is compared to literate style programming. I agree and can see the comparison. However, a main draw of literate style, as used by most tools that support it, is precisely that it lets you bend the code around a narrative. Instead, this is having to fit a narrative to the code.

As an example of what I mean, look at some places where the if chunk is as big as the else chunk. By the time you are at the else, you might have to scroll back a ton to get to what it is you are in the else of.

Now, yes, to an extent, you could split this between functions. Such that you could have:

        if foo {
          doSomething
        } else {
          doSomethingElse
        }

Literate style, though, would be more akin to

        if foo {
          <<since we have a foo, we can ...>>
        } else {
          <<Without a foo, we have to  ...>>
        }

This is somewhat subtle, but not having to define everything in terms of functions with inputs and single outputs can free certain parts of your code to just dealing with the core logic that you care to explain.

Not a panacea, but can be quite powerful.

</comment><comment><USER69> Seems like a horrible spaghetti code to me - and the verbose commenting doesn't help.

</comment><comment><USER70> This looks like pretty normal code. What is all the "space shuttle" stuff about?

The only unusual things I see are a) 8-space indentation, b) lots of "if err { return nil }", and c) lots of comments.

Aren't a) and b) standard for Go? How else is it possible to write Go code?

With less verbose error handling and 2- or 4- space indentation it wouldn't look especially "branchy".

<comment><USER71> It will actually be tabs, which is standard for Go (as per gofmt), GitHub's default tab width is 8 spaces.

</comment></comment><comment><USER72> Pattern matching would be nice in this scenario. Would help with isolating responsibility by breaking out the if statements into functions responsible only for the case they know to handle. The additional opportunities to name with more granularity could minimize the comments needed.

</comment><comment> throw-far-away It's a code smell whenever a function doesn't fit on a page or has more than 2 levels of indentation. Smaller functions are easier to test, easier to read and easier to debug. Leviathan kitchen-sink functions are a sign of slap-dash engineering.

</comment><comment><USER73> Interesting to run a "blame" on this code, and see that almost every line has been touched by a different commit, and that 41 contributors collaborated on the file.

It seems that the "do not attempt to simplify this code" is necessary rather because the cost of having so many people relearn what they already know is too large, and not because the code itself cannot be written in a simplified manner.

It's a beautiful example of the difference between real-life constraints of a codebase developed by multiple collaborators, and the _elegance_ that we strive for when coding alone.

There is no "one size fits all" coding style in software engineering.

</comment><comment><USER74> This style is common in large enterprise C++ code bases and is definitely useful when LOC exceeds a couple of 100k and the business logic complexity is high, and the project is mission critical and expected to be around for many years.

</comment><comment><USER75> I would argue that if they had solid unit tests of the expected behavior for their `pv_controller`, they wouldn't need this level of documentation - <USER2> the scary space shuttle warning - the code would self-document.

</comment><comment><USER76> Reminds me of the classic SICP quip:

"Programs must be written for people to read, and only incidentally for machines to execute."

</comment><comment><USER77> Some code do require this style.

If the code is complicated, sometimes it's better to make it extra explicit than just relying on the reader's comprehension (including empty else blocks, for example)

Because in a nested A/B/C condition it is very easy to not notice what happens in the case where A v !B v C and/or why is it different from A v B v !C especially when some of those can't happen together (but then the code does "something" and "can't happen together" means "it will happen in that very weird case")

</comment><comment> yoz-y Honestly, to me this looks like normal good code. It reads from top to bottom, exits early, does not have conditions so long that they require lines to be wrapped, it has function that are long or wide but not both... Does not seem to superfluously refactor code into functions called only once.

Maybe there are too many comments, but for code that is critical and might be harder to understand at a glance that is better.

<comment><USER78> The longest functions don't follow the same guard clause style as many of the shorter functions and I think that's a mistake. That half the file avoids else clauses and half don't tells me there's an argument here that was never adequately resolved. I think we're missing about six functions and a couple more refractors, then tone down the a couple parts of the lecture.

As it is it's obvious that many different hands were in it (and if you look at git blame, one of them doesn't know how to revert changes properly and needs to stay after school for extra lessons. If this file is so important it shouldn't have the most critical lines with a "revert changes" comment as the commit message. You done goofed, son.)

</comment></comment><comment><USER79> This seems psychotic. Why not put the same energy into rewriting this code correctly in a statically typed functional language?

</comment><comment><USER80> This is not compliant with the JPL/NASA Coding Standard: [https://lars- lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf](https://lars- lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf)

Calling this "Space Shuttle Style" is an appropriation of credibility and an insult to the engineers of STS.

</comment><comment><USER81> If you ever programmed embedded software for big companies (automotive, medical, etc) you're used to this style. Hell, at Siemens we were forbidden to even use ternary operator, a rule said it was to be replaced by a complete if/else statement no matter what.

</comment><comment><USER82> Two points...

1) One would have to make sure all the branches are accounted for during unit/integration tests.

2) The problem I am struggling with is the interviewers. So much of what I code I keep thinking about interviewers questioning it. "Why so many branches? Couldn't you have done this is in a more DRY manner? Couldn't you have done a better job at naming functions and variables so that so much commenting is not needed?".

This thing we do is truly an art form that can more easily be picked apart than properly understood. Ultimately I think we need to be like MMA fighters... able to properly pick the correct response for the situation with no ideological preference... only results matter.

</comment><comment><USER83> The key thing about complexity is that, you can move it around, but you can't make it go away.

The complexity has to be there, somehow. It's also highly subjective how one sees and grasps complexity.

Breaking code up for the purpose of reducing complexity is more often a symptom of clearing your mental space.

But IMO most often, complex code is much more well off being put in the same place, and with extensive comments too.

I also believe it's a true flaw to believe that a lot of comments are unnecessary when writing "important" code.

Comments are written in a human language, we interpret them as such. Computer language is different and it takes, more often than not, more mental power to understand and more important to change.

</comment><comment><USER84> Simplifying or not, having unit tests that cover _all_ branches will become handy.

</comment><comment><USER85> Setting aside the discussion of when, exactly, this approach is appropriate, I wish we had more languages that would make it easier and more organized. The kinds of languages where e.g. code documentation is part of the syntax, where there's a way to explicitly express various contracts (e.g. design-by-contract in the language), and where, in general, the language design errs on the side of readability over terseness.

Some examples (none of which are perfect) would be COBOL, Ada and Eiffel. But they all have their own issues, and then of course there's a question of long term support and maintenance.

</comment><comment><USER86> For a whole codebase like this check out SQLite. The best one in the world.

</comment><comment><USER87> On a related note, please note that _most_ people have the opposite issue, myself included. I know we are highly biased and tend to overcomplicate things, so I follow the KISS rule by heart.

But when I _do have to_ write complex parts of software that cannot be simplified, I will take a lot longer because I'll need to prove, first to myself, that it really cannot be simplified. Then I'll still add a big warning, either to others or to my future self (which is effectively a different person).

</comment><comment><USER88> How about: code should be self-explainable, functions should not take more than a screen, ensure behaviour with tests. Otherwise, to me it looks more like Space Shuffle style.

</comment><comment><USER10> Readability is not a valid requirement as it does not specify a valid end condition.

Likewise simplicity is not a valid requirement. Code coverage by tests, proofs and comments is.

A valid requirement could be considered complexity, number of names and entities and a lot of other linter constraints.

Heck, aggressive deduplication is not even always good.

Self similarity is not necessarily good either (the reuse of patterns) as you could have problems trying to spot the differences and special cases as they may no longer stand out.

</comment><comment><USER89> The code referenced here is extreme. It does not consider diminishing returns or acknowledge tradeoffs in readability. I would advise a more balanced approach.

A more compact style allows more code to be viewed at once making it easier to understand. Of course, taken to the other extreme, overly compact code becomes hard to read.

It's called, "the art of computer programming", because blindly applying programming principals rarely yields good results.

</comment><comment><USER90> _1\. Every 'if' statement has a matching 'else' (exception: simple error_

I've always considered this a best practice. There's rarely a good reason not to have a matching else, even if it's no more than a comment reading

// intentional NOP

or

logger.trace( "THING didn't happen, ignoring." );

Either one tells anybody reading the code that the else case was thought about and handled the way it was for a reason.

</comment><comment><USER91> Of course this can be improved and simplified. Handling 12123123 err checks is a problem of avoiding short circuit failures. That's fine, but you have multiple return values, so there's no reason not to leverage that properly...or even consistently. The whole file is littered with waiting assignment until a comparison, except in some cases or where if and elseif statements use the return values inline but not other places. It's just random.

            //checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim
            func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {

                // check if PV's DeletionTimeStamp is set, if so, return error.
                if utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
                    if volume.ObjectMeta.DeletionTimestamp != nil {
                        return fmt.Errorf("the volume is marked for deletion")
                    }
                }

                volumeSize := volume.Spec.Capacity[v1.ResourceStorage].Value()
                requestedSize := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)].Value()

                if volumeSize < requestedSize {
                    return fmt.Errorf("requested PV is too small")
                }elseif v1helper.GetPersistentVolumeClass(volume) != v1helper.GetPersistentVolumeClaimClass(claim) {
                    return fmt.Errorf("storageClassName does not match")
                }

                // function here, obviously
                err = volumeAccessModeChecks(volume, claim)

                return err
            }
            // Here's the function
            func volumeAccessModeChecks(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {
                // even the naming sucks. DISTINCT case error name
                isMismatch, volumeModeErr := checkVolumeModeMismatches(&claim.Spec, &volume.Spec)

                if err != nil {
                    return fmt.Errorf("error checking volumeMode: %v", volumeModeErr)
                }elseif isMismatch {
                    return fmt.Errorf("incompatible volumeMode")
                }elseif !checkAccessModes(claim, volume) {
                    return fmt.Errorf("incompatible accessMode")
                }
                return nil
            }

This whole function is already a separated function from the middle of the file, no reason to stop there. No need for separate files when the function calls are going to be distinct and inline beneath their usage.

</comment><comment><USER92> I imagine it reduces errors and I admit it's very tempting.

But doesn't this style add a considerable cognitive load such that thinking several layers up becomes difficult? Perhaps there is simplified documentation of lower or mid level components so that thinking on the higher levels is not so difficult.

</comment><comment><USER8> _Good_ : High-level comments that provide context, history, and motivation for the current design.

 _Also good_ : Line comments that explain cryptic details (eg, the semantics behind bit manipulations) or link to things like protocol definitions.

 _Bad_ : Line comments that simply repeat what the code does.

<comment><USER93> As a fairly junior programmer, I'll play devil's advocate on the _Bad_ bit – I find that kind of thing very helpful sometimes. Having plain english demarcations for what a piece of logic does – or where in the loop something is – can shave 80% off the time it takes to get reacclimatized when needing to make a quick change. There are moments when I know the conceptual bit that needs changing, and would prefer to hunt it in english rather than spend time translating on the fly.

<comment><USER8> Two relevant points here:

1\. My comment assumes the code itself is well-written and clear. If it is, the plain English explanation will be superfluous, and you'll be able to understand the code just as fast. If it's not, then the comment was the wrong solution to a real problem. The correct solution is to rewrite the code.

2\. What counts as "well-written code you can understand instantly" is of course experience-dependent. And not just "years of experience" dependent, but primarily "familiarity with the paradigm and style of coding experience" dependent.

Steve Yegge talks about over-commenting by junior developers here:

[http://steve-yegge.blogspot.com/2008/02/portrait- of-n00b.htm...](http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html)

I don't include that to be insulting, but because it tracks with my own experience as well.

</comment></comment></comment><comment><USER94> Why are people praising this monstrosity? Crazy complex non-simplifiable code is not good.

<comment><USER95> Yeah, 500+ upvotes on HN apparently think otherwise, but I also dare to disagree... it's not clear, despite claims to the contrary.

Comprehending this code relies on reading a long series of verbosely referenced assumptions around an implicit state machine with numerous error conditions and edge cases. The author's argument is that extreme verbosity in control structures assists with ensuring no such conditions escape an explicit code block - ie. they admit that they are (ab)using code to deal with their personal challenge of achieving a rigorous and precise conception of the problem. I would posit that approach is the wrong tool for the job, and further that they have simply failed to clearly articulate the problem, and are writing illegible code and documentation as a result. A clear symptom of the resulting fragility is the title / opening plea to others not to change their carefully constructed house of cards. Fragility does not good code make.

If I were to rewrite this, the implicit state machine and its valid transitions would be documented first and foremost, eg. with a railroad diagram or ABNF.

 _The benefit of using [a formal specification language] is that it teaches you to think rigorously, to think precisely, and the important point is the precise thinking. So what you need to avoid at all costs is any language that 's all syntax and no semantics._ \- Leslie Lamport ... via [http://github.com/globalcitizen/taoup](http://github.com/globalcitizen/taoup)

</comment></comment><comment><USER96> Space shuttle coding is like preparing code for your future self to quickly make sense of.

A key part of the software lifecycle is being able to easily onboard newcomers to be productive, or coming back to a part of a code base months, or even years later.

</comment><comment><USER97> Isn't this code style just a sign that go is lacking proper exception handling?

</comment><comment><USER98> The hubris in some of these comments is staggering. No, you wouldn't have more cleanly (and successfully) written this in $BETTER_LANGUAGE, even with your super power of perfect hindsight.

</comment><comment><USER99> Shuttle's missing a space after the comment symbol

 _/ /checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim_

</comment><comment><USER100> People seem to be missing that "simplify" here is a droll insult to too-clever hackers. The code is not too complex, it is well written and documented.

</comment><comment><USER101> This is pretty smart given the nature of open source. It's a good safeguard for someone messing with code that runs like half of cloud deployments now.

</comment><comment><USER102> This code would probably a lot shorter if every function call was not followed by a 'if err != nil' statement. This reminds me of Win32 programming.

<comment><USER103> You have to handle the errors somehow... though it's amusing that Go settled around what is essentially Java Checked Exceptions everywhere with the handicap of not being able to automatically propagate (or equivalently an Either type, albeit you can make expressive functional pipelines with that) so you always complect the attempt at doing work in the body, the ability to fail in the type signature, and the requirement to notice and handle the error at the immediate call site after the failure has wiped out any local state there may have been in the called function before it returned. (Hey, sometimes it's nice to have a way to force callers into something, but I want it as a design choice.) The notion of being able to fully decomplect and separate error signaling from error handling escapes both languages though, being that the notion is only as new as the '60s with PL/I or the '80s with Zetalisp (or modernly with Common Lisp)...

</comment></comment><comment><USER104> Way easier to maintain code that is verbose, I have never been a fan of abstracting functionality with the purpose of having less code to read

<comment><USER105> Yes, I too like to send my own electric signals to the parallel port instead of using the print menu from Word. /s

<comment><USER104> Within reason

</comment></comment></comment><comment><USER106> Porting to a language supporting exceptions would be a huge simplification. But then maybe it would stop being a space shuttle ...

<comment><USER107> Better to make blindly throwing exceptions impossible.

<comment><USER46> A good alternative is language-level support for returning early from a function with an error. Off the top of my head, both Rust and Haskell have good support for this. (I'm sure there are others, these are just the ones I know.)

Rust has a macro try!(x) that takes a Result<T, E> \- a two-variant type, either a successful result of type T or an error of type E - and translates it to, if x is the first variant, evaluate the output of try! to the value of type T inside, otherwise _return_ an error with the value of type E (on the assumption the calling function returns a Result<something, E>, too). So you can do things like `let file = try!(open(...));` and operate on the file. People liked it so much that a couple years back Rust added the question-mark operator, so you can just do `let file = open(...)?`, and chain it to `let data = open(...)?.read(...)?`. It's still visible that this is how you're handling errors, and you can always leave off the question mark and write out `match open(...) { Ok(file) => ..., Err(error) => ... }` instead, if you'd like.

Haskell has its monads, which for the present purpose can be interpreted as just a wrapper type. Given a wrapped object of type T, you can give it a function that takes a T and returns a similarly-wrapped object of type U, and have it apply the function to the data. If the wrapped object is in a failure state, it can choose to "apply" the function by just not calling it at all and instead returning the same failure state. Haskell has special notation with the "do" keyword for calling several monadic functions repeatedly, where it looks like you're writing regular, imperative code and assuming errors don't happen. But again it's obvious when you're using it and you can always handle the exceptional case specially as soon as you want.

<comment><USER108> You missed the E in Result<T, E>, by the way.

<comment><USER46> Thanks, fixed - I was trying to gloss over it for the sake of readers for whom X<Y> itself isn't familiar syntax but I think it makes more sense this way. (I'm also glossing over the fact that try! will convert error types, I think?)

Or pretend I meant io::Result :)

</comment></comment></comment></comment></comment><comment><USER109> I find I often write code in comments first w/ the business logic, and then flesh out the comments with actual code.

</comment><comment><USER110> Where's the test ? How people test this piece of code ? Test is what matters, automatic or manual.

</comment><comment> an-allen I'd like to see Uncle Bob do a point-by-point critique of this... "piece of work"

<comment><USER46> What is Uncle Bob's claim to fame? What has he written that is production- ready and sturdy and has held up to change?

I'm sure he can have opinions - he is very experienced at having convincing- sounding opinions on software development. But where is the test of whether he's right?

</comment></comment><comment><USER111> This is awesome. I have learned a ton about the volume controller just from the comments!

</comment><comment><USER112> Nice. At some point one rolls up your sleeves and says "right, this part is important and needs to work and _I_ need to be sure I have got it right" At that point space shuttle style works pretty well (usually for me I am writing some security / control dispatch for the umpteenth time)

</comment><comment><USER113> this is how my code looks until it's done, where i take out all of the nonsense and make it unmaintainable, shooting myself in the foot for any development i need to do on it in the future. love it :D

</comment><comment><USER114> yesss thought I was the only one that thought this style was a good idea ... Makes my last company look foolish and explains why most of the devs weren't as productive as they could have been.

<comment><USER115> That sounds like some dangerous over-attribution

<comment><USER114> Dangerous is not delivering on time because you want the code to be fancier than it should be or needs to be when all you had to do was write it out plainly and leave obvious comments.

</comment></comment></comment><comment><USER116> Ah, I love this so much.

</comment><comment><USER117> What's up with that tab size? Is that normal for go code?

<comment><USER118> Go uses tabs instead of spaces and Github displays them as 8 character width. It can get annoying and there are several extensions to change this behavior. Tab Size on Github [1] is the one I personally use.

[1] [https://github.com/sindresorhus/tab-size-on- github](https://github.com/sindresorhus/tab-size-on-github)

</comment></comment><comment><USER119> I love it so much.

</comment><comment><USER120> ctrl+f 'err != nil', 88 matches

</comment><comment><USER121> God, Go is tedious to read.

Also, just use a code formatter that rejects any incorrectly styled code.

</comment><comment><USER122> someone please introduce idris to the k8s team.

</comment><comment><USER123> emm... no, please. like the enthusiasm though

</comment><comment><USER124> Kubernetes, eh? (strikes through its name on my list)

<comment><USER125> Why? Does this file/comment cause you to lose confidence in the project in some way?

I'm genuinely curious to understand the reason for your comment.

<comment><USER126> Code that "can't be refactored" is a huge smell. This code can be written in a simpler and easier to follow fashion even if the authors of the code were unable to do so. The proof of that is the thousands of free software projects of equal level of complexity whose code bases are a joy to read.

</comment></comment></comment><comment><USER127> this is how I wish all code looked.

</comment><comment><USER128> The amount of circlejerking in this thread is unbelievable. Go is a horrible language, and if this code were posted anonymously, these same idiots calling it "the jazz music of software development" and "space shuttle style" (copied verbatim from the actual code comments to boot) would be deconstructing and denigrating it to the last fine detail. Hilarious.

</comment><comment><USER129> Sounds like a job for typed pattern matching.

See rusts, match operator. The operator won't even allow your code to compile if all branches are not accounted for.

</comment><comment><USER130> I tend to wrap the if statement in the function as much as possible, so that the code as a whole presents a sequential pipeline structure. Keep the code concise and readable.

MyBlog: The Pure Function Pipeline Data Flow [https://github.com/linpengcheng/PurefunctionPipelineDataflow](https://github.com/linpengcheng/PurefunctionPipelineDataflow)

</comment><comment><USER131> I wonder if this arises there because people get moved and would otherwise receive lots of clarification requests regarding the implementation from a new maintainer. It is easier than maintaining a separate wiki page that might lose track of changes.

</comment><comment><USER132> "premature optimization is the root of all evil" \--knuth

</comment><comment><USER133> Violates title guidelines.

[https://news.ycombinator.com/newsguidelines.html](https://news.ycombinator.com/newsguidelines.html)

<comment><USER134> Guidelines != Rules. This a direct quote, so I'd think it'd be disingenuous to lowercase it. Probably good that guidelines aren't rules, even though people confuse them more than I'd like.

edit: After I posted this I saw the title was lowercased and dumbed down. Unfortunate that the term 'guideline' has been misapplied again, making things worse, but at least there's some irony to get a chuckle at given the article's subject matter.

</comment></comment><comment><USER126> Is there any evidence that writing code in the demonstrated way produces higher quality? No? None at all!? Then why should I believe it? I might as well embrace healing and homeopathy too...

I'd rather write my code like its written in the Linux kernel. There is no evidence that that style is better either, but at least Linus has provided loads and loads of arguments in favor of it on a mailing list.

</comment><comment><USER135> While I can understand the basic philosophy, it seems an unfortunate example to pick something that had 2 catastrophic failures out of 135 launches. Although, I suppose, neither of them were due to software...

<comment><USER136> There were many other close calls, most having to do with the thermal system on the external tank, which is what damaged Columbia. It was a known issue for almost the entire program.

As you said, nothing having to do with the control system.

</comment></comment><comment><USER137> Although I think this is great, this reminds me of a talk Bryan Lunduke did where he says CS/software development is not a profession yet. I love the flexibility software devoplmentgives to every cs, programmer, developer but when you think more about it, that is not the same for other jobs/professions. Professions have standard guideline, procedures to follow. Everyone is doing any language they want, design patterns they just read from a random article, 100s of tutorials on one subject. But are all languages/paradigms/architecture equal? Should there be language _only_ used in some industries to keep consistency? Doctors can't just try a new technique, neither do lawyers. Not saying it is bad, but something I think more thought needs to be put into.

<comment><USER35> I would say that "Everyone is doing any language they want, design patterns they just read from a random article, 100s of tutorials on one subject" is far from being true anyway.

That might be true if you live in a cave but when you are working on a team of 6-8 people with a team lead then basically none of that is true and you are forced to follow others' decision and everything is decided for you (instead of you to make decisions) no matter if you like it or not.

Of course some might say but then you have to make compelling arguments to raise your concerns and being heard but that's beyond the point and that's politics that most people (including me) despise. As a software engineer your only choice to make those decisions you mentioned is that you are a manager of some sort or you work completely alone.

And for some reason most developers accept this hierarchical relationship in their daily professional life but still pretend that they are allowed to make decisions by themselves instead of pointing out the implicit forces which rule their daily lives.

And I like to call out this line of thinking because it is pushing this liberal agenda that you are the sole reason for your luck or failure which is not true at all. Not even close to reality.

Actually many thought leaders in our industry for example Uncle Bob anticipate that our industry MUST and/or WILL be regulated (if by self-imposed regulation or external one is again beyond the point) otherwise the whole industry would lose credit. And I fully agree with that.

Not only because of credibility reasons but also because it makes the implicit subordinate relationship that most developers are blissfully unaware of, more explicit.

<comment><USER137> > That might be true if you live in a cave but when you are working on a team > of 6-8 people with a team lead then basically none of that is true

Yes, I agree if you have an established team and there is a strict hierarchical development cycle/roles then rules will be enforced. But how about other team dynamics or lone developers that push their code into the world. How many js libraries import explicitly or implicitly an addition library (too many to count on top of my head but not enough to bother writing a script for you to show). There is a lot of bad code out there that were created by bad _untrained_ tech managers and lone coding wolves because some standards have not yet been refined yet or agreed upon(standards like ssl, aes encryption).

> liberal agenda?

You lost me there? And maybe I lost myself as well

> Uncle Bob When I said Bryan, i misspoke and was refering to Uncle Bob. But > do you agree with self-imposed or external? They lead down very different > paths</comment></comment></comment>


The New York Review of Books turns 50 - <AUTHOR> http://www.washingtonpost.com/lifestyle/style/the-new-york-review-of-books-turns-50/2013/11/06/5e031f64-4703-11e3-a196-3544a03c2351_story.html <comment><USER2> "The 50th anniversary issue is gaudy with intellectual firepower. Four Nobel Laureates have bylines. U.S. Supreme Court Justice Stephen Breyer muses on reading Proust. There's the transcript of a long-lost lecture by T.S. Eliot. British novelist Zadie Smith writes about her dad and their walks in public gardens."

It has its quirks and limitations -- Anglophilia, Isaiah Berlin, clubby-ness ("the New York review of each other's books), East-coast myopia. But it is consistently interesting, smart, confident, and deep.

</comment><comment><USER3> I feel I have to promote the Times Literary Supplement. I personally have always gotten somewhat more out of it. The NYRB feels a tad parochial (inward- looking) at times, its subject matter a tad more restricted than the TLS. But it's great they got Zadie Smith to write a piece for the anniversary issue, I love her voice. Actually a bit ashamed to say I haven't been keeping tabs on the both the TLS and the NYRB - I used to spend hours with stacks of them to pass the time and discover new pastures in uni - in a while.

<comment><USER4> I don't agree about NYRB being parochial and restricted. If anything, it's one of the more expansive magazines in terms of subject matter covered. While I don't know the Times, I can't think of a literary magazine more dedicated to covering the entire world (geographically, politically, intellectually) as NYRB.

For example, NYRB has a _lot_ of foreign reporting and analysis; this last year they have had a ton on Egypt, Iraq, Iran, Libya and a wealth of other countries. Many of the subjects covered — books, art, people — are not American.

And while their stable of writers certainly lean in a specific political direction, NYRB tends to favour just quietly reporting the facts, as opposed to bombastically trumpeting political opinions the way that, say, The Economist (which recently insisted that western leaders must bomb Syria) frequently does.

There are admittedly exceptions. NYRB has traditionally been critical of Israel, for example. But they are generally critical of war-mongering, persecution and nationalism, so it's hard to argue that they are being one- sided in that sense.

</comment></comment><comment><USER5> I'll offer my congratulations as well - it feels like it's just been able to freshly tap the nerve of what lies beneath cosmopolitan America, and for that alone it won't go stale for a bit. The LRB, even through the same means, has ended up sounding like it fights a rear-guard action.</comment>