Introduction to Databases - <AUTHOR> https://class2go.stanford.edu/db/Winter2013/preview/

<comment><USER2> Both in timing and in content this could be a good lead-in to the University of Washington's Intro to Data Science class that looks like it will have more of a focus on 'big data', NoSQL, Hadoop, data mining, etc.

<https://www.coursera.org/course/datasci>

<http://news.ycombinator.com/item?id=4881581>

</comment><comment><USER3> The original Database class is available [1] via Coursera for self study.

[1] <https://www.coursera.org/course/db>

<comment><USER4> Is there a list anywhere of Coursera courses that have a self-study option? Unless there's something I'm misunderstanding about what that option means, these are the only Coursera classes I'm ever likely to use, because of my schedule. It seems odd that they don't appear to differentiate them.

<comment><USER3> There are two more of them that I know of:

CS 101 - <https://www.coursera.org/course/cs101> Compilers - <https://www.coursera.org/course/compilers>

I will check again later tonight and see if there are more I will add them to the list at <http://www.class-central.com/courses/selfpaced>

<comment><USER4> Wow. Thank you very much!

</comment></comment></comment></comment><comment><USER5> Did anyone that took the 2011 course share his experience?

<comment><USER6> I took it at Stanford, but it was using the same online content.

The course is probably way more theoretical than you'd expect. It goes a lot into relational algebra, schema design, and UML.

The online SQL quizzes are pretty cool little puzzles but the only truly exciting part of the class was creating a website using a large database as the final project, which I can't imagine will be offered in the online version.

If you don't know anything about databases or are trying to learn SQL, it could definitely be worthwhile.

<comment><USER7> It sounds like I'll hopefully get something out of it, given I'm purely self- taught post-high school. Some rigour to my existing practical capacity would be useful.

Do you believe it'll offer this?

<comment><USER8> A: Yes, I think so. I'm self thought guy myself, at least, when it comes to programming, and I really enjoyed watching the relational algebra videos and then the SQL ones (never got to the modelling part though, got all my learning time sucked by a big work project)... _go through them at 1.5x or 2x speed and you won't regret it, at least if you had no encounter with relational algebra before_ , as it feels good to know there's some nice and simple math behind SQL :) (though now I want even more to shoot the guy that invented SQL's ugly syntax and all the database implementors that piled tons of "semi-compatible" shit on top...)

</comment></comment></comment></comment><comment><USER9> That Flash intro pic made me think I was watching the trailer for "Stepmother III"

</comment><comment><USER10> I wonder why the new course is not part of Coursera...

<comment><USER11> In the video, Prof. Widom mentions that the platform they are using now, Class2Go, has been developed at Stanford and is open source. A quick look at <http://class.stanford.edu/> shows that it depends on external components - YouTube for video, and Piazza for forums - but it's good to have an open platform, and one of the aims is to avoid lock-in of content.

</comment></comment><comment><USER12> I attended two different courses on Coursera and i hope that i will pick more courses there DB is also most important course for me.</comment>


A positive leap second will be introduced at the end of June 2015 - <AUTHOR> http://datacenter.iers.org/eop/-/somos/5Rgv/latest/16

<comment><AUTHOR> How are my systems affected?

RHEL - [https://access.redhat.com/articles/15145](https://access.redhat.com/articles/15145)

Ubuntu - [https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1020285](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1020285)

Windows - [https://support.microsoft.com/en- us/kb/909614](https://support.microsoft.com/en-us/kb/909614)

AWS - [https://aws.amazon.com/blogs/aws/look-before-you-leap-the- co...](https://aws.amazon.com/blogs/aws/look-before-you-leap-the-coming-leap- second-and-aws/)

Google Cloud - [http://googlecloudplatform.blogspot.com.au/2015/05/Got-a- sec...](http://googlecloudplatform.blogspot.com.au/2015/05/Got-a-second-A- leap-second-that-is-Be-ready-for-June-30th.html)</comment>


Push Browser App Should Make Chrome's Apple Fans Happy - <AUTHOR> http://www.thechromesource.com/push-browser-app-should-make-chromes-apple-fans-happy/

<comment><USER2> Chrome To Phone actually does a little more than just shunt links between the two devices: it actually dispatches to an appropriate application based on the content you send.

For instance, highlighting a phone number opens the dialer with it pre-filled. Manually modified routes on Google Maps are preserved when being sent, and also open in the native Maps application. YouTube links open in the YouTube app. Selected text gets sent to the device's clipboard.

It's pretty fantastic. Hopefully Push Browser can grow those features as well.

</comment><comment><USER3> I've actually just been using the Notifo extension[1] and Notifo iPhone app.

Interesting that your original post[2] announcing the launch wasn't as well received as this secondary source/blogpost ...possibly timing of the post?

[1]: [https://chrome.google.com/webstore/detail/lgffhepmapgeepjnhc...](https://chrome.google.com/webstore/detail/lgffhepmapgeepjnhchaabmaoijfcnhi) [2]: <http://news.ycombinator.com/item?id=2269900>

</comment><comment><USER4> I'm using Handoff for this (<https://www.handoffapp.com/>) which includes extensions for Chrome, Safari and Firefox.

<comment><AUTHOR> Handoff does not send links from iOS to the desktop.

</comment></comment><comment><USER5> <http://www.pastefire.com> lets you send any selected text from anywhere on your mac (and PC? not tried) via right click - free!

</comment><comment><USER6> I'd love to see this for android too, so I could share between all devices with one system.

<comment><USER7> Chrome to Phone has been out since last summer.

<comment><USER2> I think sjs382 is looking for a system that can send to _both_ Android and iOS devices with one click. If Push Browser added Android support, it would fit that bill.

</comment></comment></comment><comment><USER8> I heard Wired did a whole issue on how this is the future.

<comment><USER9> Mondo 2000 is restarting their magazine for the iPad and the first issue will also cover this.</comment></comment>


Courselib online courses - <AUTHOR> https://play.google.com/store/apps/details?id=org.courselib.www.courselib <comment><USER2> Good job, well curated courses and video from youtube. Good collection of educational resources.</comment>


AnalyticsMD (YC W15) Applies AI to Optimize the ER - <AUTHOR> http://techcrunch.com/2015/01/28/analyticsmd/

<comment><USER2> I know a lot of ER doctors. They all hate the software that they have to work with; especially the "resource control" software that stands between them and the drugs and tools they need to treat people. This seems like another tool in that direction. It seems designed to take decision making away from doctors and put it in the hands of management.

What do you expect that this tool will do for the working environment of ER doctors and nurses? Or the relationship between them and their patients?

<comment><AUTHOR> Good question. ER doctors hate when software gets in the way of their clinical decision making. We deliver recommendations to the front line managers but they decide what to act upon. One of the most frustrating things for the doctors often is when they are waiting to treat the patients but can't because there are no beds, or not enough staff or labs are not coming back. Our software anticipates those problems and recommends taking out those bottlenecks in advance.

Our hope is that we will make the day of the staff in the ER much less stressful and allow them to focus on spending more time with the patients.

</comment></comment><comment><AUTHOR> Just launched our product on TechCrunch. Helping hospitals run smoothly a challenging problem but one we care a lot about.

If any of you want to talk about this or have stories from waiting in the ER or a doctors office please share :)

<comment><USER3> Congrats!

<comment><AUTHOR> Thanks @mendelc

</comment></comment></comment><comment><USER4> How has this performed in the real world? Has it been tried in high traffic areas? (i.e. chicago/nyc)

<comment><USER5> Does it get reinforced for doing an obviously bad or good job?

<comment><AUTHOR> Yes. Our data feeds include the outcome variables we are optimizing for which helps the algorithms retrain as new patterns emerge.

</comment></comment></comment><comment><USER6> Can you tell more about DecisionOS? Is this something you've built inhouse or is it based on MLLib etc?

</comment><comment><USER7> How does this data enter your system?

<comment><AUTHOR> Unfortunately, there aren't any great APIs in the health IT world but we integrate with various hospital systems. We do not ask staff to enter any additional data than what is already in these systems

</comment></comment><comment><USER8> Is there any lash back from integrating with Epic within the Hospitals?

</comment><comment><USER9> What is your tech stack?</comment>


Amazon Connect – Simple to use, cloud-based contact center - <AUTHOR> https://aws.amazon.com/connect/ <comment><USER4> This is a fantastic move for Amazon and I'll tell you why. The cost of long distance is nearing 0 and application providers are making bank. The pricing is also extremely disruptive. Most contact centers price minutes/DIDs just like Amazon but ALSO charge a per-agent per-month fee. [1]

All of the contact center solutions mentioned so far were customers of mine at MagicJack. We did wholesale long distance for them. The one trend in the industry is that long-distance continues to fall fast, but the pricing of telecom-related apps stayed the same.

Since I am no longer under NDA, the average cost of long distance (US Domestic) at MagicJack when I left in 2013 was $0.0017/minute!!

For those saying contact centers won't move over because the investment - <USER2> will tell you that we lost and gained 1,000 agent operations over 10% cost savings every single month.

[1] - [http://blog.kunnect.com/2014/10/how-much-does-cloud-based- ca...](http://blog.kunnect.com/2014/10/how-much-does-cloud-based-call-center- software-cost-comparing-prices-and-features-among-top-vendors/)

<comment><USER5> 2 other reasons i like:

amazon can integrate with their marketplaces...giving them an inherent ability to enrich and monetize contact center which others don't have.

trojan horse for improving their AI services - nice data to train lex and polly on - and for lex and polly to self-learn on...

<comment><USER6> I would be surprised if amazon has access to the voice recordings, maybe something can be found in the terms of use?

Customer data is pretty closely guarded at aws, I would be surprised if they would jeopardize uptake by medical and financial sectors for the sake of a small amount of training data (when they already have all the data they could want from amazon.com)

</comment></comment></comment><comment><USER7> I built a Five9 instance from the ground up in support of a ~20 person customer service center several years ago.

Switching costs, even for that little 20 person shop, would be insanely high to move to Amazon between training reps, rebuilding custom reporting, recreating workflows, DID switching, etc.

And Five9 matches several of the amazon features - cloud based, minimal contracts (month to month at last check), decent API integration support, object-oriented set-up UX, etc.

I am excited about Amazon's entry in this space to push everybody forward, but I think they're going to make more impact forward than penetrate existing organizations.

<comment><USER8> This has been mostly true for any new business or technology. The "hockey stick" growth point often occurs when it becomes more difficult for existing businesses not to use it.

</comment></comment><comment><AUTHOR> It's interesting that Amazon continues to move up the stack. This can't be great for folks like Five9, inContact, Genesys, etc. And it's probably incrementally negative for Zendesk, RingCentral, and Twilio - where some percentage of customer use cases is tied to contact centers.

<comment><USER9> Twilio seems to be promoting this on their blog[0], so can we assume it's powered by Twilio services?

[0] [https://www.twilio.com/blog/2017/03/supercharge-your- amazon-...](https://www.twilio.com/blog/2017/03/supercharge-your-amazon- connect-flows-using-aws-lambda-node-js-and-twilio.html)

Edit: yep

[https://investors.twilio.com/news/all-news/press-release- det...](https://investors.twilio.com/news/all-news/press-release- details/2017/Twilio-Extends-Relationship-with-AWS-through-Support-of-Amazon- Connect/default.aspx)

<comment><USER10> I wonder if AWS will turn to Twilio to replace the SMS capabilities of SNS which are aging and limited with respect to modern features such as emojis and long messages.

<comment><USER11> Twilio did a presentation at re:Invent last year talking about how they power AWS SMS messages.

<comment><USER10> I had they're one of the providers but I've also heard, from a smaller Twilio competitor at a conference, that AWS utilizes several SMS providers, which might make sense regarding the extra limitations.

</comment></comment></comment></comment></comment><comment><USER12> This feels a lot like Amazon's ecommerce activities. Since Amazon own the platform in ecommerce, they can detect which goods are most successfully sold, sell those goods themselves, and use their scale and distribution to muscle out competitors.

Now since Amazon owns the cloud infrastructure, they can detect which apps are among the most successful (e.g. customer service apps) and build only winners. Again, they can use their scale and distribution to muscle out competitors.

<comment><USER13> You seem to assume that they have bad intentions. They are just increasing the number of value-add services they offer. They aren't necessarily trying to muscle out competitors, competition in the marketplace is ultimately great for the consumer.

<comment><USER14>
      > competition in the marketplace is ultimately great for the consumer

Not necessarily. History is replete with monopolies that arise through competition; cabals, sweetheart deals and other secret arrangements designed to fool the consumer into believing there is competition where there is none; race to the bottom in terms of quality vs profit margin; exploitation of underprivileged workers; and so on.

Not to say that all competition is bad, just that market competition is not a panacea.

<comment><USER15> _into believing there is competition where there is none_

It feels like you're validating the original point here. These secret arrangements are not competition and instead consolidation. If market competition did exist, free from illegal practices, the product that provides the most value for a given consumer will win that customer's business.

You're instead talking about why anti-competitive practices are bad... Which is why we have the sometimes-inept DOJ.

</comment></comment></comment></comment><comment><USER16> They are doing this to train Lex and Alexa on conversations. Remember Tesla has better data therefore it has the betters self driving car. The end goal is of course to lose the human operator.

</comment><comment><USER17> While Americans are worried about jobs lost due to H1b, outsourcing or offshoring, such automation will be the real job steeler. It even steels the outsourced job back to US!

Curious to see the effect of Amazon Connect on call centers in US and around the world.

<comment><USER18> As an aside, the level of over-employment in the US and the UK blows me away at times. I walked by tiny hole-in-the-wall type restaurants that could seat maybe 20, and they had valet parking (because why not?). Two valets were working 4 car spaces.

In the UK, a postman walks into a 100 apartment building and goes door to door putting the mail and packages into the slot for each individual unit.

Anywhere else in the world, you park your own car, and your mailbox is at the entry of the apartment building so the postman can access all 100 mailboxes at once.

</comment></comment><comment><USER19> Maybe because i'm a noob on telephony dev. but what's a "soft phone"...does that mean that the humans who receive the calls don't actually use traditional phones (like landlines or mobile phones), but rather via their web browsers?

Silly question: but if i didn't want my folks to use web browsers, and simply wanted to route a call to whomever is on call (and that person works remote, let's say), I wonder if possible to simply route the calls to that person's mobile phone?

<comment><USER20> Yes, that's basically the idea, a phone number that doesn't belong to a physical device but can be reassigned as needed/ on a schedule.

<comment><USER19> Thanks. It seems - based on other comments - that this is likely a service for bigger customers, so i would guess those customers know what these terms mean.

</comment></comment></comment><comment><USER21> Two thoughts to add:

1) If you're a contact center veteran but new to AWS, know that evaluating any just-launched service against existing competition is unwise. Check back a few months after they've had time to incorporate customer feedback. AWS released over 1000 updates to the platform in 2016, and Amazon as a whole deploys software about once per _second_. Think twice about brushing this off like EMC, Oracle, HP, and Cisco did around 2010.

2) Lambda is very powerful and should be a key focus of the discussion. Here's an article demonstrating why. [https://www.twilio.com/blog/2017/03/supercharge-your- amazon-...](https://www.twilio.com/blog/2017/03/supercharge-your-amazon- connect-flows-using-aws-lambda-node-js-and-twilio.html)

</comment><comment><USER22> _" Amazon Connect supports voice interactions for incoming and outgoing PSTN telephony...It supports DTMF input, text-to-speech output using Amazon Polly, which can optionally be combined with Amazon Lex...for natural language interactions."_

Sounds like you can build a fairly sophisticated robodialer with it. That's not terribly easy to find out in the market. Hope they have some controls to curb abuse.

</comment><comment><USER23> Looks really cool, I wish openvbx was still developed

<comment><USER13> Twilio got out of that business a long time ago in order to focus on the core product, which was the right decision at the time and ultimately still now. There are loads of Twilio customers who make their living sell contact center solutions built on top of Twilio and that is exactly what Twilio wants.

 __Disclaimer: I am ex-Twilio __

</comment></comment><comment><USER24> Can reps take calls on their mobile device? I can't seem to figure that out. If so, this could be a reasonable replacement for Grasshopper.

<comment><USER25> Yes there is such an option to forward inbound calls to an external number.

</comment></comment><comment><USER26> Really nice! Now I just need to wait for Brazilian numbers support to move for my current SAS provider.

</comment><comment><USER23> Bandwidth uses this? I thought they were a telecommunications company

<comment><USER27> Maybe they use it so that their customers can get through to their customer support agents whenever they're having one of their outages.

</comment></comment><comment><USER28> why is alexa mentioned here? will this promote answer-by-alexa-the-robot or still it's the legacy answer-by-human-style contact center?

</comment><comment><USER29> If someone can figure out for me if adding support for webRTC VIDEO is viable, that would be amazing. I'm driving 6 hrs and can't research it.

<comment><USER30> There is a 100 ways to integrate it with WebRTC. You don't mind wasting 6 hours of your life driving, but can't be bothered to do your own research, let me guess, you are a sales person, selling cloud stuff.

<comment><USER29> Thanks...That was helpful. ;) Have a look at my profile if you want to know what I have done. Driving with kids is what you do as a parent on spring break.

As for the question, I was trying to discern if amzn was making the video conf functionality (debuted with the Kindle Fire) for customer service available, or if integration was contemplated and discussed in the content. It does not appear as such.

I wish I could give you 100 uovot s to encourage more of your behavior.

</comment></comment></comment><comment><USER31> Some things:

(1) I do not like putting all my eggs in one basket for telecom. I don't care if Amazon is managing the API server for my grandma's heart monitor - I never trust one TSP. One TSP = one point of failure. I hope they do something to address this. (and please don't bother replying with some assumption that multiple paths disqualifies the need for redundancy through multiple TSPs)

>Amazon Connect runs on Amazon Web Services proven infrastructure operating 42 Availability Zones within 16 geographic regions around the world. This makes Amazon Connect more highly available, fault tolerant and scalable than would be possible if a contact center solution was run from a single data center.

Amazon Connect is only offered in US East as of right now. I wonder what that means for reliability/fault tolerance. Does the user have to initiate geographical replication?

(2) I do not like relying solely on an internet service for telephony/CC. I will rely on it for _most_ of my telephony/CC _most_ of the time, but I see no reason why CC offerings shouldn't have some kind of offline component. I hope they do something to address this concern.

(3) I see they have released the "Streams" API[1]. It's well documented, which means I can create similar API calls for an offline replacement. I'm glad they addressed this somewhat, although I wish they would consider making a useful multipurpose soft phone so I can use SIP registrations from other systems in an emergency.

(4) The limit of 10 DIDs seems exceptionally low. Sure, once the call hits Amazon, it can go through its routing steps, but Amazon is not in control of where the customer gets the number. DIDs often serve an analytical function, especially when that's the only useful data (besides Caller ID) coming in from the PSTN. It would seem more reasonable to max out at 100 (yes even for a starter account). I hope they do something to address this concern.

(5) Getting to use their ASR is a big deal - especially over the PSTN. When I realized I'd have to write an MRCP plugin just to reliably stream audio to the Google Speech API, I gave up on that dream. I wish Google would address the concern of PSTN to the Google Speech API... I don't care about any other call center doodad, but being able to leverage a speech processing - <USER3> Google's or Amazon's - API is _a really big deal_. The fact Amazon has made this available over the PSTN with the possibility of having an API make decisions from speech is exciting.

All in all, this is nice and I'm sure they have rough edges they'll polish. At the end of the day, their speech stuff is something I'll _definitely_ be using, the other stuff does not make me feel confident it's redundant/fault- tolerant. There are just too many points of failure.

[1]:[https://github.com/aws/amazon-connect- streams](https://github.com/aws/amazon-connect-streams)

<comment><USER32> Item #5 is the key. Nuance dominates the ASR market for IVR based speech applications. BlueWorx has a MRCP product for IBM Watson. I press the Google team constantly to provide ASR for IVR solutions. We move most customers off clouds because of either (1) poor telecom performance/quality, and (2) lack of enterprise ASR for IVR self-service.

</comment></comment><comment><USER33> They are making money at multiple points:

1\. Charging you per-minute for use of the service.

2\. Charging you a per-DID fee per day of use. Why? You are already paying for the service, and for the VOIP termination. BTW at Amazon scale, the DID numbers are either free or less than 10 cents/month per DID.

3\. Charging you (in the USA at least) for the actual VOIP calling.

With 1) and 3), a USA call costs you 0.0048 cents per minute on inbound. Under usual circumstances, inbound calls to USA numbers are free.

They will also (should you request it) record the calls and store them in S3...

<comment><USER34> Is this pricing that unusual? Almost all the other products I've looked into had pricing plans where you pay a per user license, plus the cost of a DID and usage. A couple offered just per user license, but when you did the math you could have people to be on the phone for 10 hours a day before you started saving vs per minute prices

<comment><USER35> Yes it is very unusual in this industry. As a matter of fact, it is so unusual that it will continue to exist for the foreseeable future since most companies depend heavily on the licensing model to survive. It's the heart of their operation - changing it would most likely have an adverse impact on their business.

But, it is going away with companies like Fenero, and now Amazon Connect, leading the way.

Amazon Connect has a lot of catching up to do since it is no where near the feature set required to run a real contact center (it can't even support blended agents or call outcome dispositioning and reporting!)

I totally understand why Amazon Connect may seem like a big deal for those of you outside of the space, or that aren't real close to the various advanced technological capabilities in this industry.

Check out this analysis for more: [http://blog.fenero.com/amazon-connect-is- not-only-over-price...](http://blog.fenero.com/amazon-connect-is-not-only- over-priced-but-it-lacks-critical-features-and-is-a-lackluster-foray-into-the- contact-center-software-space)

</comment></comment></comment><comment><USER36> I thought Amazon should focus on IaaS. I don't think this service is a IaaS, so don't like it.

<comment><USER37> Do you realize how big the Amazon conglomerate is? They do far more than just some EC2 virtual machines, even if just looking at AWS alone.

</comment></comment><comment><USER38> What does this have to do with "cloud"? Seems like confusing messaging.

If I'm not paying by the CPU hour, then it isn't "cloud".

<comment><USER39> Hmm, I've never heard that definition. Maybe "cloud hosting". But in general, "cloud" software just means hosted somewhere else and usually accessed via a browser or mobile app rather than with a local install.

<comment><USER38> You just described every website ever.

<comment><USER40> I build "cloud" contact center software. To most people it just means no servers at the customer site. To discerning customers, cloud means horiz- scaling, while hosted just means we manage the servers for you.</comment></comment></comment></comment>


Applying the Linus Torvalds "Good Taste" Coding Requirement - <AUTHOR> https://medium.com/@bartobri/applying-the-linus-tarvolds-good-taste-coding-requirement-99749f37684a#.7axbqnfqm <comment><USER2> I'm reminded of a quote from Moore in "Thinking Forth":

"A lot of conditionals arise from fuzzy thinking about the problem. In servo- control theory, a lot of people think that the algorithm for the servo ought to be different when the distance is great than when it is close. Far away, you're in slew mode; closer to the target you're in decelerate mode; very close you're in hunt mode. You have to test how far you are to know which algorithm to apply."

"I've worked out a non-linear servo-control algorithm that will handle full range. This approach eliminates the glitches at the transitioning points between one mode and the other. It eliminates the logic necessary to decide which algorithm to use. It eliminates your having to empirically determine the transition points. And of course, you have a much simpler program with one algorithm instead of three."

"Instead of trying to get rid of conditionals, you're best to question the underlying theory that led to the conditionals."

That's part of a _chapter_ of the book called Minimizing Control Structures. Forth guys are crazy about taste, and if I've learned anything from reading their stuff, it's that chasing tasteful programming to its end gets very hard.

OP is right on the money. The hard thing is that it is a creative process, and takes a real understanding of the problem you're solving to do it. Worst of all, aside from the feeling of solving a puzzle well, the benefits only begin appearing much later. I'm glad the kernel team takes it seriously.

<comment><USER3> > That's part of a chapter of the book called Minimizing Control Structures.

Since the book is creative commons and freely available, I decided to download the book and have a look. Figure 8.1, the "automatic teller" example is just downright hilarious. The author presents the code and throws a challenge at the reader: "Easy to read? Tell me under what condition the user's card gets eaten." Here's the code:

      IF card is valid DO
        IF card owner is valid DO
          IF request withdrawal DO
            IF authorization code is valid DO
              query for amount
              IF request <= current balance DO
                IF withdrawal <= available cash DO
                  vend currency
                  debit account
                ELSE
                  message
                  terminate session
              ELSE
                message
                terminate session
            ELSE
              message
              terminate session
          ELSE
            IF authorization code is valid DO
              query for amount
              accept envelope through hatch
              credit account
            ELSE
              message
              terminate session
        ELSE
          eat card
      ELSE
        message
      END

(hopefully no transcription errors from copying out of the PDF…)

Yes, it's easy. It gets eaten if the owner is not valid. Took one glance.

The thing that makes me laugh is that the example is contrived. This is the sort of thing code editors solve. Even though I could quickly glance at it and decipher the conditionals by eye, if I were working with this I'd still throw it into an editor that shows me code scope. That makes it trivial and removes any chance of error. This is a problem that has been solved.

I'm sure I will get a lot of responses saying I've missed the point, and yes I'm aware that I've dodged it, but the author acts like the problem of navigating nested conditionals is somehow _impossible_ , which I think is ridiculous. Not only do lots people do it every day, not only are there tools that help us do so, but there's pretty much no way to exist in this world without depending on software that is written this way (ever looked at the source for GCC, to pick one example?) Not saying it's right, but it's clearly not a deadly problem.

<comment><USER4> Just the raw formatting of that could be improved, by cuddling up ELSE IF from separate lines.

Aren't there some END tokens missing? Let me put them in:

      IF card is valid DO
        IF card owner is valid DO
          IF request withdrawal DO
            IF authorization code is valid DO
              query for amount
              IF request <= current balance DO
                IF withdrawal <= available cash DO
                  vend currency
                  debit account
                ELSE
                  message
                  terminate session
                END
              ELSE
                message
                terminate session
              END
            ELSE
              message
              terminate session
            END
          ELSE
            IF authorization code is valid DO
              query for amount
              accept envelope through hatch
              credit account
            ELSE
              message
              terminate session
            END
        ELSE
          eat card
        END
      ELSE
        message
      END

Okay, now:

      IF card is valid DO
        IF card owner is valid DO
          IF request withdrawal DO
            IF authorization code is valid DO
              query for amount
              IF request <= current balance DO
                IF withdrawal <= available cash DO
                  vend currency
                  debit account
                ELSE
                  message
                  terminate session
                END
              ELSE
                message
                terminate session
              END
            ELSE
              message
              terminate session
            END
          ELSE IF authorization code is valid DO
            query for amount
            accept envelope through hatch
            credit account
          ELSE
            message
            terminate session
          END
        ELSE
          eat card
        END
      ELSE
        message
      END

Okay, just one ELSE IF; not much opportunity for that.

<comment><USER4> On that topic, I did a somewhat weird thing in C yesterday. I took code like this:

      for (;;) {
        /* original big loop */
      }

and turned it into this:

      if (compatibility_with_old_version) for(;;) {
        /* original big loop: same indentation level! */
      } else for (;;) {
        /* rewritten new loop */
      }

I.e.

      if (...) for (...) {

      } else for (...) {

      }

Works for me.

</comment></comment></comment></comment><comment><USER5> I dunno, the first example seems unsatisfying. The original has that ugly condition, the "good" version seems overly clever. And for all the talk of taste and aesthetics, both versions ignore an elephant in the room: defensively dealing with `entry` being absent from the list.

Not that I've never abused addresses like this. But having written this multiple times, I currently prefer something like this:

      remove_list_entry(entry)
      {
          if (head == entry) {
              head = head->next;
              return;
          }

          for (prev = head;  prev->next;  prev = prev->next) {
              if (prev->next == entry) {
                  prev->next = prev->next->next;
                  return;
              }
          }
      }

There's still an `if`, but it isn't so bad since it's an early exit. What is "tasteful" about hiding the fact that one of the cases is _far_ simpler than the other? There's conditionals and then there's conditionals. There's cases and then there's cases.

The other benefit of this approach: you eliminate segfaults by construction, because the `while` has been replaced with a much more _normal_ `for` loop iterating through the list. Keeping it normal is 80% of the secret to avoiding security holes.

Rather than appealing to something nebulous like "taste", I prefer to focus on concrete functional benefits. What is a situation where someone using or modifying this function might be subtly led astray? That seems a better guide.

 _(Earlier version posted on reddit:[https://www.reddit.com/r/programming/comments/59cq8r/applyin...](https://www.reddit.com/r/programming/comments/59cq8r/applying_the_linus_tarvolds_good_taste_coding/d97pcrl) )_

<comment><USER6> Screw 'taste', go for _obvious_.

If you're at BigCo and your codes going to be maintained by disinterested drones/ random contractors/etc, obvious code is better.

And lack of checking on _entry_ pissed me off too.

<comment><USER7> I say screw 'taste' and 'obvious' and instead go for _it has high coverage unit tests and lots of them_.

You can always go back and make it look pretty safely with good tests.

I just love code snobs that think their code is so good they don't need tests.

<comment><USER8> > You can always go back and make it look pretty safely with good tests.

Yeah, but you won't. I think that's part of the reason why people care about "taste". I want to maximize the chances that essentially the first draft is good enough to be maintained for as long as possible, because years of hard- won experience has taught us that it will.

<comment><USER7> > Yeah, but you won't. I think that's part of the reason why people care about > "taste".

Ahh but you eventually will (at least in my experience). If you don't need to the code either doesn't matter (dead code) or works just fine.

I think I have looked at my own companies entire code base a couple of times. Do I see nasty crap... all the time. And I often fix it for good taste when it is really bad but I have to say the value prop isn't very good compared to adding tests or other automated validation (including automated profiling and dead code analysis).

Kernel code and in particular C are sort of special cases because they are hard to test and performance is generally a high concern. But for many other higher level languages and problem domains this is not the case.

I have been meaning to look how at how much code bases change overtime. In the case of Linux I wonder how much of the Kernel code has stayed the same (lets say over a 5 year period). Probably not a ton but I bet for other domains particularly business software the code either just dies or changes dramatically over time.

Then there are I suppose other domains where the code really can't physically change often (ie space probes and embedded devices).... for those systems I really really hope they have lots of tests.

</comment></comment></comment></comment></comment><comment><USER9> For my money, Linus's example of "good taste" gives up rather a lot of clarity to achieve succinctness. The original is simple and clear. His preferred version is shorter, but also harder to understand because of its use of a complicated indirection. And that's not good taste. It's just showing off.

"Programs must be written for people to read, and only incidentally for machines to execute." ― Harold Abelson, Structure and Interpretation of Computer Programs

<comment><USER10> I completely agree (tho you're getting downvoted by others).

Linus's code here is 'clever'... but not good, simple code.

<comment><USER11> It's a long time since I wrote much C but Linus' version seems like idiomatic C to me. The use of pointers in C is an ordinary thing and those who write a lot of C should be fluent in their use.

It's interesting to apply the same technique to other languages. I have to use VB.net most of the time so here are implementations of the tasteless and tasteful versions in VB (untested so there might be bugs). Even in VB the tasteful version is shorter and, I think, clearer.

        Module Module1

          Public Class ListEntry
            Public value As String
            Public [next] As ListEntry
          End Class

          Public Head As ListEntry

          ''' <summary>
          ''' Straight translation of Torvalds' tasteless version.
          ''' </summary>
          ''' <param name="entry"></param>
          Sub RemoveListEntry(entry As ListEntry)

            Dim prev As ListEntry = Nothing
            Dim walk = Head

            ' Walk the list
            While walk IsNot entry
              prev = walk
              walk = walk.next
            End While

            ' Remove the entry by updating the head or the previous entry.
            If prev Is Nothing Then
              Head = entry.next
            Else
              prev.next = entry.next
            End If
          End Sub

          ''' <summary>
          ''' Straight translation of Torvalds' tasteful version.
          ''' </summary>
          ''' <param name="entry"></param>
          Sub RemoveListEntry1(entry As ListEntry)

            Dim indirect = New ListEntry
            indirect.next = Head

            ' Walk the list looking for the thing that points at the thing that we
            ' want to remove.
            While indirect.next IsNot entry
              indirect = indirect.next
            End While

            ' ... and just remove it.
            indirect.next = entry.next

          End Sub

End Module

</comment></comment></comment><comment><USER12> I was given a piece of advice very early on in my career that I've always been grateful for, which is fundamentally the same as this. IF and FOR are both code smells.

One case of this is just simplifying loops with some functional goodness

      var listOfGoodFoos = new List<Foo>();
      for(var i = 0; i< listOfAllFoos.Count; i++)
      {
         if(listOfAllFoos[i].IsGood)
             listOfGoodFoos.Add(listOfAllFoos[i]);
      }
      return listOfGoodFoos;

VS

      return listOfAllFoos.Where(x => x.IsGood);

But perhaps a more interesting point is it can also be a a sign of DRY gone wrong - two things that aren't actual repeats of each other, but just similar code, are smushed together with lots of IFs hang around to make it actually work.

A connected piece of advice was "it is easier to push things together than pull them apart" so err on the side of assuming two bits of code are not the same, knowing you can refactor them together later (probably only a few hours later) if it turns out they are in fact pretty similar.

<comment><USER13> It's not simplifying it though, it's just hiding the complexity in syntactic sugar. I prefer the first way of doing things vastly over the second. Yeah, it's more code, but it's also more or less "what is actually happening", instead of an euphemism which has to be unpacked.

<comment><USER14> > it's just hiding the complexity in syntactic sugar.

And that complexity is only written once, instead of multiple times for a single project

You can have as many FOR and IF branches that you want, but only if they are all bugless!

<comment><USER13> Actually, it's written exactly as often as the original construct.

The idea that writing more than 5 letters, or a for loop here and there, is this giant cesspool source of errors is totally alien to me. Of all the ways in which my programming sucks, this was never among them. So thanks for you permission, I'll use it wisely :P

</comment></comment></comment></comment><comment><USER15> These are great examples, and they hint to, but do not mention, the big counterpoint: development time. In his own examples, the author admitted that though the code was ugly, it worked. He then _spent extra time_ reworking the existing code to make it, well, prettier.

"If I had more time, I would have written a shorter letter." \-- Voltaire

The problem is that, in many (most?) professional settings, the developer is under huge pressure to _get shit done_. Not get it done perfectly, not done beautifully, but just done in the first place. We rarely have the leeway to spend extra time refining existing code, existing _features_ or _bugfixes_ , to make them prettier. It's gotta be done, and it's gotta be done yesterday because maybe some other part of the project is blocked because of it or some customer paid for it and it was supposed to be done last month or it broke and why the hell isn't it fixed yet!?

Some projects, I daresay mostly open-source projects, can afford to be detached from the pressure of deadlines that corporations require, and reject code that isn't to their quality standards. Sadly, that's not the case for most of us.

<comment><USER16> "If I had more time, I would have written a shorter letter." \-- Voltaire

You're quoting Pascal, not Voltaire ;)

<comment><USER17> "The worst thing about the internet is how quotes are always misattributed." \- Albert Einstein

</comment></comment></comment><comment><USER18> Linus' "good" version has a McCabe cyclomatic complexity of 2, whereas the "bad" version has a value of 3. So, objectively, one could argue there is improvement there (albeit small). Validation of the "good" version will be easier (e.g. code coverage testing) with fewer paths through the code. Additionally, a lower cyclomatic complexity typically implies less stress on the developer's working memory while reading code (since you don't have to consume an internal brain "register" holding the result of a conditional while following the flow of control).

<comment><USER19> I thought the same.

On the other hand it took me a bit of time to figure out what's going on.

But I'm not C dev, so that could be the issue here.

<comment><USER20> Serious question: after figuring it out, did you have a somewhat better grasp of linked list mechanics than before?

<comment><USER21> I had a better grasp of how to work with them (am not who you replied too).

I never had to build my own linked list though. I never took those basic courses.

</comment></comment></comment></comment><comment><USER22> > it only performed 256 loop iterations, one for each point along the edge

 _alarm bells_

There are only 252 points along the edge. This code will act on each corner twice. If you were performing an operation like `+= 1` on each edge element, this code would be wrong. When you copy and paste it later and change all the `= 0` to something else, you might end up with an unfortunate surprise.

Once I saw this mistake in the 2nd code example, I guessed it would also appear in the 3rd one. Sure enough, it does. This is just as _unsavory_ to me as the original code.

I'm not sure if the author is here or not, but if you are, can you see the fix?

<comment><USER23> Here's my fix:

      for (i = 0; i < GRID_SIZE - 1; ++i) { // Note the "-1"...

          // Top Edge
          grid[0][i] = 0;

          // Bottom Edge
          grid[GRID_SIZE - 1][GRID_SIZE - i - 1] = 0; // Reverse the order: from left to right

          // Left Edge
          grid[GRID_SIZE - i - 1][0] = 0; // Reverse the order: from bottom to top

          // Right Edge
          grid[i][GRID_SIZE - 1] = 0;
      }

This way, for every row/column, the loop acts on all but the last cell, which is actually the first cell of some other column/row.

<comment><USER24> I feel like for the each side you could actually handle two items per iteration, one forwards _and_ one backwards. That way your iteration count could be halved.

<comment><USER25> That doesn't reduce the number of cells touched, and would make the algorithm more complicated. It would also probably hurt cache locality. Going backwards is also pointless complication, you could just as easily cut into two sections and go forward in both.

And furthermore why split in two? Why not split the range into three sections, or four, or N and completely unroll the loop?

Probably not a good-tasting construct at all.

</comment></comment></comment></comment><comment><USER26> Not being used to C syntax, I took this as a typo at first:

        indirect = &(*indirect)->next;

The position of the parentheses make it look like you're dereferencing only (* indirect). But on second look, you need the parens there so that it's (* indirect)->next as opposed to indirect->next. Then the & operates on the whole thing. I'd be tempted to wrap it in a second set of parens for clarity, but perhaps it's entirely obvious to a programmer who's actually used to using pointers. IE:

        indirect = &((*indirect)->next);

<comment><USER10> To me, its 'clever' code.... i.e. it should be simplified.

This is not good code, it requires too much thought to realise what its doing.

<comment><USER26> It's busier to look at due to the syntax of the language, but if you're comfortable with pointers one could argue that it's conceptually simpler than the first example. And since linked lists are all about pointers, operating on the pointer directly seems logical.

That said, for someone unused to the syntax (as I am!), I agree that it is definitely harder to mentally parse. So which is objectively better probably depends on your audience.

<comment><USER16> >So which is objectively better probably depends on your audience.

I guess when your audience is kernel developers, this isn't that much of a problem...

<comment><USER10> not true at all.... kernel developers are not mythical beasts, they're just regular low-level developers. Nothing special.

I've got 20 years experience developing this kind of stuff and to me, its not as simple as it could be, therefore it could be better.

<comment><USER27> You have 20 years of experience on this kind of stuff and don't recognize the textbook example code for handling the head pointer case of a linked list? Well, okay...

(It's at least 23 years old because I learned from textbooks that have this example code way back then. It probably dates all the way back to K&R.)

<comment><USER10> What textbook would that be exactly?? (not that it matters)

The point isn't "can I understand it"...

the point is "Would someone who hadn't seen it before have to do another mental operation to understand it?"

...and yes... dereferencing _is_ another operation you have to do in your head to understand it.

<comment><USER27> Well, I'm at work so I can't dig around my library but it was easy enough using date range restrictions to find an academic example in Google that dates back to '99: [http://cslibrary.stanford.edu/105/LinkedListProblems.pdf](http://cslibrary.stanford.edu/105/LinkedListProblems.pdf) . (It was actually the first hit.) Searching further backwards in time is left as an exercise to the reader.

Multi-level pointer dereferencing is a fundamental C / assembly language skill and Linus' example was just about the most basic example there is.

<comment><USER10> We will have to agree to disagree on that point.... And I have just as much experience in c as Linus.

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER28> I don't know how to reconcile Linus's track record is of indisputable brilliance and success (I use Linux and Git on a daily basis and am eternally grateful for both), with the fact that I would absolutely DESPISE working with a peer with the kinds of attitudes and opinions on coding that Linus has.

I think the problem I have is that a lot of people use Linus's examples and stories as justification for their own suboptimal interpersonal skills, overly-clever code that only they understand, but without the same level of brilliance or track record to justify it.

Ultimately I think Linus's contributions to Software are pantheon, but he should not be looked to for imitation or lessons. His lessons for success are detrimental to the vast majority of software engineers.

<comment><USER29> You make claim after claim, and I think they _do_ need substantiating evidence. After all, I find it highly unlikely that if he were even 10% as bad as you make it sound he would be the head of one of the most successful projects - especially since everybody working with him does so voluntarily. There would have been breaks long ago. The fact that the Linux kernel held together under the original author loudly speaks against assumptions of "bad interpersonal skills" on the side of Linus.

<comment><USER17> I won't argue with your main point, but a fair share of kernel devs are probably not working there voluntarily, since they write kernel code for their employer.

<comment><USER30> I'd expect that most devs capable of writing reasonable Linux kernel code would not have difficulty finding employment somewhere else doing something else.

</comment></comment></comment></comment><comment><USER31> I don't know why I'm even replying, this will get so much hate here, oh well...

1\. Just because things aren't done "the way you would do them" doesn't mean they're "bad" or "wrong".

2\. If you're not on a solo project, I've found writing correct but less "clever" code to help shorten ramp-up time for new devs and be more beneficial to future maintainability of the code-base and system.

TL;DR; Swapping values by XOR'ing may look elite and clever but hurts you in the long run.

<comment><USER32> Re: #2 - in Linux case, double-pointer list removal succinctly illustrates the minimum C proficiency needed for tinkering with kernel code.

That is, not every project has "shortening ramp-up time" as a priority. In quite a few cases non-trivial code doubles as filter for less skilled devs.

<comment><USER33> >In quite a few cases non-trivial code doubles as filter for less skilled devs

Right, until the less skilled dev it's you, months later after you moved on to other stuff, and have to get back and fix some clever shit you wrote but don't understand anymore.

Unless you're doing numeric or performance critical work, code should be optimized for readability and maintainability.

<comment><USER34> If this example is too "clever" for someone, even sight unseen, they aren't (yet?) cut out to be a kernel hacker. I don't disagree with your general principle, but the linked example is idiomatic and understandable C for someone with a decent knowledge of the language, which is (I'd imagine/hope) the standard expected of contributors to Linux.

<comment><USER33> Actually I believe this particular example is basic and pretty understandable C.

I was talking about the more broad idea of knowingly writing clever code to raise the entry barrier for new devs. Or just writing clever code for whatever the reason. It's almost guaranteed to backfire, to new devs who will have to maintain it or to yourself, when you will have to read it in a less _smart_ moment.

<comment><USER34> Entirely agreed.

</comment></comment></comment></comment></comment></comment><comment><USER35> I've been told many times that it's better to eliminate edge cases. I still don't really believe it as a universal law.

When explaining the algorithm "remove an element from a linked list" to someone else, I would say "starting at the head, go along the list until you find the element; then delete the element". When explaining the algorithm "delete an element from a linked list", I would say "if you're at the head, update the head to be the next element; otherwise update the `next` property of the previous element to be the `next` property of the current element". It's so naturally a two-case problem that I'd be really surprised if anyone came up with the one-case answer first. Therefore, the two-case answer is the more readable to someone who has not seen the code before, because it corresponds to their intuition about how the algorithm should work.

As a bonus, it's clear to me that the naive algorithm is correct, but I have to do mental work to convince myself that the one-liner algorithm is correct. (I'm saying nothing about the code; only the algorithms.)

I agree much more with the reduced complexity of the later example (initialising the edges of a square), and I actually think it's worth double- counting the corners in this instance because the code is so much cleaner. (EDIT: Although I suppose the easy fix doesn't detract from the ease-of- reading, so actually it's avoidable.) In that instance, there's doubt about which is the natural algorithm to pick: one could conceivably come up with "initialise the top and bottom, then initialise the left and right", or "initialise the zeroth element of each side, then the first of each side, then…" as one's first attempt at solving the problem. Therefore I like this particular simplification.

<comment><USER36> > It's so naturally a two-case problem that I'd be really surprised if anyone > came up with the one-case answer first.

[Raises hand] I always did it Linus' way in C (way before him); I don't remember if I ever had the need in assembly before.

<comment><USER35> Fair enough. I stand surprised! How would you describe the algorithm to a friend, then?

</comment></comment></comment><comment><USER37> I think "competitive" (i.e. solving algorithmic challenges for fun) coding really gives you some insight into how to write code that's short and to the point. The user with the most reputation on LeetCode, for example, consistently posts solutions that are surprisingly short, efficient, and readable.

[https://discuss.leetcode.com/user/stefanpochmann](https://discuss.leetcode.com/user/stefanpochmann)

(some random examples)

[https://discuss.leetcode.com/topic/18731/7-lines- c-c](https://discuss.leetcode.com/topic/18731/7-lines-c-c)

[https://discuss.leetcode.com/topic/16988/7-lines-3-easy- solu...](https://discuss.leetcode.com/topic/16988/7-lines-3-easy-solutions)

[https://discuss.leetcode.com/topic/33430/6-lines-o-log- min-m...](https://discuss.leetcode.com/topic/33430/6-lines-o-log-min-m-n-ruby)

<comment><USER38> The code might be short and to the point, but it definitely is not easy for me to understand!

The code feels like a bit like clever perl one-liners.

<comment><USER39> Or you could just loop n-1 times and adjust the array indices in the loop body, so that each statement only deals with one corner.

</comment></comment></comment><comment><USER40> Both versions suck. If "entry" is not found in the list, the code will run off the end of the list, either de-referencing zero and faulting or going off into junk, depending on how the list ends.

Writing low-level list manipulation more than once sucks. It leads to bugs. Such manipulation should be encapsulated. That's why we have containers in modern languages. The Linux kernel is still C, not C++, which leads to too much of this sort of thing.

<comment><USER41> I think practicing C programmers are using the list implementations that were given to us two decades ago. Or any of the newer alternatives. And if they aren't, it's not because of the language.

</comment></comment><comment><USER42> Here's even more "tastier" 2 lines version:

      remove_list_entry(entry)
      {
          for (indirect = &head; (*indirect) != entry; indirect = &(*indirect)->next);
          *indirect = entry->next;
      }

The big problem: both Linus's and above versions don't handle the case if entry wasn't found, for example, if entry was null. This is the fundamental issue with trying make code overly compact: sometime you _lose_ the sight of important edge cases. Segfaults are not tasty. I generally prefer to write code that reflects my thought process and avoid unnecessarily try making it compact. As Knuth had said "Programs are meant to be read by humans and only incidentally for computers to execute". Uglier versions allows to explicitly documents edge cases. This enables future maintainer to make sure these cases are covered when s/he makes code changes. Obviously taking this to another extreme would ruin this. The better taste lies somewhere between the compact Linus's version and some zeolite's too verbose version.

Small problem: Another thing to think about is extra pointer redirection required in Linus's code. This is fine for most cases but if I was dealing with very large list over and over then that's unnecessary perf hit.

<comment><USER43> The 'entry wasn't found' case is an entirely different issue than what Linus is showcasing. It may or may not be relevant for the particular function, depending on its contract and documentation.

</comment></comment><comment><USER44> I would argue for the last example it is better to write split the loop into four. I believe the intention is even clearer (because you are doing four different things), and that it is also faster even when optimizations are off due to better cache behavior. It may also make a smart but not "sufficiently smart" compiler to transform two of the loops into simple memset.

</comment><comment><USER45> The author doesn't mention that the grid being initalized is square, and simply describes it as grid[rows][cols]. However, all his solutions are only correct for a square grid.

One solution for arbitrary dimensions could be

        for (i = 0; i < rows; ++i) {
            grid[i][0] = 0;
            grid[i][cols - 1] = 0;
        }

        for (i = 0; i < cols; ++i) {
            grid[0][i] = 0;
            grid[rows - 1][i] = 0;
        }

<comment><USER46> You're updating the corners twice. Not really a problem with a simple assignment, but as no_protocol pointed out elsewhere [0], it could be if you ever wanted to change that to, say, an increment.

Replace your second for statement with

        for (i = 1; i < cols - 1; ++i) { ...

and you're golden.

[0] [https://news.ycombinator.com/item?id=12794235](https://news.ycombinator.com/item?id=12794235)

<comment><USER45> You're right, my version is unoptimized because I was trying to keep the code neat as in the article. I think that optimizing the code for hypothetical future reuse is a bit premature. You could make a performance argument, but this optimization is going to prevent just 2 memory accesses, which aren't going to matter much compared to all the rest. If I was chasing performance I would start by memset'ing the top and bottom edges since they're contiguous in memory.

<comment><USER45> My mistake - the optimization would prevent four memory accesses. Still O(1).

</comment></comment></comment></comment><comment><USER47> The code in the examples is not valid in any historical version of C. The use of the -> operator with an implicit int as the left argument ("entry" in the examples) was only valid from 1975 in Unix C (but not in GCOS C) until K&R C in 1978. The use of C++ style comments ("//") is only valid in standard C since 1999.

There's no point in arguing over pseudocode as if it's C.

</comment><comment><USER48> The root of the problem is that "the thing that points to an entity" is not a consistent concept in this kind list. Sometimes it's "head", sometimes it's an entity's ->next. I wonder what Linus would think of implementing the linked list with a dummy head node, having no value and pointing to the first entity. Personally, I think that would be tasteful. It allows for simple loops like the "good taste" one, but you don't have to think so hard about how to implement a simple operation like _remove_. You don't need the added indirection.

<comment><USER17> It's one more pointer that you have to resolve, everytime you do something with the list. Sounds smelly to me.

<comment><USER49> Depends on where you store it. If you're just passing around node pointers, then you could create the dummy node on the stack only when you need it and it's the same indirection cost as the "indirect" pointer. If you've got a "list" struct that you're passing around (pretty unlikely in C), you could embed the dummy node directly.

</comment></comment></comment><comment><USER50> The example there about edges on an array is something I've had to directly deal with myself when I implemented a multidimensional image-processing function for GNU Octave. The problem is to find connected components in a binary image, where voxels are either 0 or 1. You want to find all the islands of ones, and you want to be flexible if diagonals count as being connected or not.

The problem, of course, is that along the edges you don't want to check for neighbours outside of the image boundary. I found no good way to do this for an n-dimensional image, after a few attempts of writing very complicated code. In the end, I ended up padding the whole image with a boundary of zeros, iterating over the padded image with an "if(current_voxel)" conditional that skipped checking for lit neighbours around the boundary, and when checking for lit neighbours at the original image's boundaries would give no neighbours at the padded zero boundaries.

The code was cleaner, but I incurred a big realloc, because N-dimensional images in Octave are stored as contiguous Fortran-order (column-major) arrays. I'm still looking for a better solution to this problem.

So, how do you do this cleanly?

<comment><USER51> Isn't it simple enough to make three bounds checks to essentially do the same thing you did with the zero padding? You can even make it a function

        is_in_bounds(x, y, z)

<comment><USER50> It's n-dimensional, not 3-dimensional.

Also, it's really slow and wasteful to be doing bounds-checking for each voxel of an image that is almost completely not a boundary, whereas you can't avoid checking if each voxel is lit. :-)

</comment></comment></comment><comment><USER52> One anti-pattern I've seen a few times, across multiple codebase and companies, is the for i in 1...cases: switch(i)

To me, his first example fits this perfectly, except he is using ifs instead of a switch. Basically, if you are generating a big, trivial sequence and then filtering it down afterwards, think harder and probably there is a way to generate the sequence you are actually after directly.

<comment><USER53> > One anti-pattern I've seen a few times, across multiple codebase and > companies, is the for i in 1...cases: switch(i)

Also known as the "for-case" loop. Version 2 is a prime example of this, and what not to do. It processes case 1, then case 2, then case 3, then case 4. The author rewrites it as one loop of 64, but four loops of 64 each would also be acceptable.

> To me, his first example fits this perfectly, except he is using ifs instead > of a switch. Basically, if you are generating a big, trivial sequence and > then filtering it down afterwards, think harder and probably there is a way > to generate the sequence you are actually after directly.

Now you're talking about a different problem. The conditionals in the first version do not iterate through like code doing "switch(i)". I agree that it's better to directly generate than to filter, but that's a totally separate anti-pattern.

</comment></comment><comment><USER54> This article made me think of this Gordon Bell quote:

"The cheapest, fastest, and most reliable components are those that aren't there."[1]

That quote is a reminder to me that there is a certain artistry behind engineering anything.

[1] [http://quotes.cat-v.org/programming/](http://quotes.cat-v.org/programming/)

</comment><comment><USER55> Maybe I'm wrong about this but I noticed that the code didn't call free() to the element that has breen removed. That would cause a memory leak. Am I missing something here?

<comment><USER56> The caller still holds a pointer to the element and can free it. I would argue that delegating the responsibility of freeing the element to the caller is more performant, since that allows the code to reuse that list element and insert it into a different (compatible) list.

That's the kind of performance/ease-of-use trade-off that sounds reasonable in an open source project with strict code reviews (but in very few other places)

</comment></comment><comment><USER57> All due respect to Linus, but the second example is much less readable. Proof of that: the code was reduced in half, but the amount of comments was doubled.

I think concepts like "elegance" and "good taste" of code should exist, but they are obviously subjective. My choice of good taste always considers readability first.

<comment><USER49> I'm pretty sure that the comments are for people who Linus _doesn 't_ want contributing to the kernel. This code would likely have no comments at all if checked into the Linux kernel because it would be obvious to everyone allowed to do commits.

</comment></comment><comment><USER25> Oh good lord. That edge-initialization code made my jaw drop. Did he not think about the problem _at all_ before putting code down?

</comment><comment><USER58> I know Sufficiently Smart Compilers are a running joke, and I know a lot of people think the idea is a bad one, but come on...this should be the job of a compiler. The first example is _way_ more understandable. Yes, it branches, and yes it is more code and less efficient. But a compiler _should_ be able to derive the more efficient version from the more understandable code. And it's a shame that it doesn't.

<comment><USER59> I think Linus argued that the second version is more understandable.

In fact if you read the article there's no claim being made that the second version is more efficient, and I don't think it is

</comment></comment><comment><USER60> For the curious like me who wanted to see the assembly for the Linus examples and compare [https://godbolt.org/g/sqdBrf](https://godbolt.org/g/sqdBrf). Most importantly they have the exact same number of branches and their loops are exactly the same size 4 instructions on all opt levels greater than 02. The setup code for the first one is much longer.

<comment><USER60> Here is also a somewhat representative example of various grid initialization pay attention to version 3 where the compiler unrolls the loop in O3 its likely the fastest version. [https://godbolt.org/g/mMBhuW](https://godbolt.org/g/mMBhuW)

</comment></comment><comment><USER61> Often I find myself solving problems in a single performant SQL with lateral/cross joins before hitting the business logic code in order to simplify the logic part into a single loop with no conditionals/edge cases.

Turns out this is not the best practice because you will have to explain all about your clever use of olap functions and lateral joins to someone less knowledgeable who has to append to your code.

<comment><USER62> I would argue that having developers that don't understand and won't bother to learn SQL working on application dependent on SQL-based DBs is the not-best- practice there, not proper and efficient use of SQL by developers who do know what they are doing.

<comment><USER61> You are right, of course, but they have "working knowledge" of sql which is adequate for most reports and operations.

Just not the "high level" SQL someone armed with the knowledge of functional programming could conjure when faced with the alternative of writing lots of nested conditional statements and loops in an imperative language because it would bore him to pieces.

</comment></comment></comment><comment><USER63> You can think of your grid array as a contiguous piece of memory. I would do:

      bzero(grid, sizeof(int) * COLS);
      bzero(grid + COLS * (ROWS - 1), sizeof(int) * COLS);

      for (int i=1; i < ROWS-1; i++) {
        *(grid + (i * COLS)) = 0;  /* set left col to 0 */
        *(grid + (i * COLS) + COLS - 1) = 0;  /* set right col to 0 */
      }

</comment><comment><USER64> > To the best of my ability to discern, the crux of the "good taste" > requirement is the elimination of edge cases, which tend to reveal > themselves as conditional statements. The fewer conditions you test for, the > better your code "tastes".

 _looks at his Swift code and gulps_

</comment><comment><USER65> Eventually you will realize Linus is a bad person to take advice from and stop idolizing him.

<comment><USER66> Examples of good persons to idolize, please? :-)

<comment><USER65> I'm an anonymous internet poster, I don't have a suggestion for who you should idolize. But picking Linus is a red flag. His man-child entitled attitude, condescension, arrogance, etc, make him a parody of a toxic developer that ruins teams from the inside out. Normalizing and uplifting that behavior makes us all worse off.

</comment></comment></comment><comment><USER67> Does it follow that attempting to write code that is closer to functional style also improves the code's "tastefulness?" I'm under the impression that better functional code contains fewer branches.

</comment><comment><USER68> Is it just me or does the grid initialization example seem extremely contrived?

<comment><USER69> I thought that too. I found it hard to believe that anyone would write either of the first two versions without having thought of the 3rd - or, you know, just having 2 or 4 separate for loops. Maybe there was something about the problem's context that the author left out of the post though?

</comment></comment><comment><USER70> Both are correct, one is considered better based on a subjective assessment. People who disagree with that the version a person selects is __objectively __better have no taste.

</comment><comment><USER71> I'm a bit confused. If the entry is not in the list, does Linus's while loop throw a seg fault? Or are we assuming that the list contains the entry?

</comment><comment><USER19> Well, the "good taste" example has a lower cyclomatic complexity, so it is at least a measurable change.

</comment><comment><USER72> Every time you write an 'if' and do not stop for a moment to consider it, a kitten dies.

</comment><comment><USER73> Speaking of coding niceties, when I started branching out from bash into a 'real' language, Python, I couldn't find a switch statement. A colleague of mine said that Python didn't have one, and that switch statements were a 'code smell'. I didn't really understand that, and asked about those times that you genuinely could use a switch statement, and the answer was "just use a long if-else function". I can't remember his justifaction for it, so clearly it didn't stick

I still don't see the real pragmatic difference between a switch statement and a long if-else function - anyone feel like ELI5'ing it for me? Switch statements just seem more concise and readable to me...

<comment><USER74> Switch statements have fall-through behavior that you need `break` to avoid (in most languages); sometimes this is what you want, but only rarely.

One trick I've seen people do in Python is to use a dict; define lambdas for each case, and then key the dict on your value that you would switch on, and invoke the lambda (or use existing functions).

        def fake_switch(self, thing):
            {
                'foo': self.do_foo,
                'bar': self.do_bar,
                'frog': self.blast_vent_core
            }[ thing ]()

I am doing a poor job of explaining _why_ one might want to do that, but one advantage is that you can verify that the right callbacks were called in tests, and also verify that each callback behaves right when invoked, since they are just references to methods or functions. I'm not sure if doing this would get marks for cleverness and testability, or would get one criticized for excessive cleverness. As the reviewer of the code when a coworker wrote it, I recall liking it, though.

<comment><USER73> Thanks to both of you for the info. I haven't played with lambdas much yet, perhaps this is the time to start :)

<comment><USER75> Lambdas in Python are somewhat limited - the syntax allows for only one expression. You can use inner (nested) functions however.

</comment></comment></comment></comment><comment><USER76> I think the main lesson that's there, is that in edge cases, it is sometimes helpful to work with pointers which point to the structures you're actually working with, instead of considering the structures themselves. This especially seems to work for getting rid of null checks.

This takes some getting used to, but it allows you to write more efficient code. I would do this in kernel development (smart people, high demands on performance), but I would not recommend to write code like this is enterprise software.

When you zoom out a bit, and describe the task with natural language, you can also see that this might be a good idea: "Find the node that is equal to entry, then, if the previous node exists, set the 'next' pointer of the previous node to the 'next' pointer of the current node." sounds a lot more tedious than "Find the pointer that points to entry, and set it to the 'next' pointer of entry.".

This also works for more complicated tasks:

      // removes all instances from the linked list and return the number of entries removed
      int removeentries(valuetoremove, list)
      {
      	removedentries = 0;				// how many entries we've removed
      	prevpt = NULL;					// pointer to previous
      	entrypt = list.head;			// get pointer to first node

      	// walk the list (be careful, head can be a nullpointer)
      	while (entrypt) {
      		if (*entrypt == valuetoremove)
      			if (prevpt) {
      				prevpt->next = entrypt->next;
      				removedentries++;
      			}
      		prevpt = entrypt;			// save current node as prev for next node
      		entrypt = entrypt->next;	// move to next node
      	}
      	return removedentries;
      }

can be re-written to:

      int removeentries(valuetoremove)
      {
      	removedentries = 0;				// how many entries we've removed
      	indirect = &head;				// points to the current node

      	// walk the list
      	while (indirect) {
      		// remove current entry from list if its value equals valuetoremove
      		if (indirect->value == valuetoremove) {
      			*indirect = *indirect->nextpt;
      			removedentries++;
      		}
      		indirect = indirect->nextpt;
      	}
      	return removedentries;
      }

</comment><comment><USER77> Sandi Metz has a talk where she speaks about her dislike for _if_ [https://www.youtube.com/watch?v=OMPfEXIlTVE](https://www.youtube.com/watch?v=OMPfEXIlTVE)

<comment><USER17> Thanks for the link. I found the talk very insightful.

I would imagine Linus to disagree with Sandi's approach, though. She is never eliminating the _if_ (as in: the conditional jump), just moving it from plain sight into the magic of dynamic method dispatch.</comment></comment>


Blowing Up: How This One Fund Blew Up Overnight – And What We Can Learn from It - <AUTHOR> https://palisade-research.com/blowing-up-how-this-one-fund-blew-up-overnight-and-what-we-can-learn-from-it/ <comment><USER2> This is the good old fallacy of not looking at long enough time horizon and estimating information content in recent variance in addition to not setting up a robust strategy.

Usually taking off robustness for small short term profit is not worth it.

The usual thing is if the maximum observed variance vastly exceeds any current trend, you definitely should not gamble in this way as the volatility is high. Complete but easy calculation would allow him that the assumption he made is baseless. (Take a peek at variability in 70s, current blip is way below that.)

As for "black swan" events and general risk bounds, he probably did not gamble with money he couldn't afford to lose. That's not necessarily true for his clients though.

Bankruptcy with limited liability is a valid exit strategy and any investor should be aware of that risk strategy.

</comment><comment><USER3> Blowing Up: a crappy webserver. Here's a mirror: [http://archive.is/ezjyH](http://archive.is/ezjyH)

</comment><comment><USER4> [https://news.ycombinator.com/item?id=18496870](https://news.ycombinator.com/item?id=18496870)

</comment><comment><USER5> Ok, so don't they teach beginning options traders about naked call options??</comment>


'Critical Thinking' discourages ideas. [Patrick Finn audio and TED video] - <AUTHOR> http://www.cbc.ca/radio/thecurrent/the-current-for-september-07-2015-1.3217914/critical-thinking-discourages-ideas-says-professor-1.3217951

<comment><USER2> This is absolutely true. Critical Thinking _does_ discourage ideas - namely, poorly thought out and stupid ones. There's absolutely nothing wrong with using creativity to solve problems, however, at some point, you have to think critically about those solutions if you ever have any hope of _actually_ solving problems. But, Why stop there? If we're going to get rid of critical thinking, why not just throw out the whole of the scientific method as well? We'll all find ourselves in the middle of a new Dark Age at the wrong end of a dowsing rod .</comment>


ActiveRecord and Azure - <AUTHOR> http://renderedtext.com/blog/2012/09/04/activerecord-and-azure/

<comment><USER2> I am absolutely astonished someone would even consider deploying a Rails app on windows.

<comment><USER3> The app itself is on Linode, the database is on Azure. We were contracted at a point when we could not influence that.</comment></comment>


Beginning machine learning by a software engineer in a hurry - <AUTHOR> https://medium.com/totvslabs/beginning-machine-learning-by-a-software-engineer-in-a-hurry-ad58412145b8 <comment><USER2> Nice, thanks for sharing your experiences! It's really inspiring for other engineers

<comment><AUTHOR> Thanks!</comment></comment>


An Ode to Computer Shopper - <AUTHOR> http://www.theatlantic.com/technology/archive/2013/07/an-ode-to-em-computer-shopper-em/277713/

<comment><USER2> Computer Shopper was the multi-vendor catalog for computers back when a dial- up BBS was all the networking you could expect at home.

There were also articles, every now and then something interesting like reviews of early PC UNIXen, scattered in with hardware roundups that often took the form of "200 laser printers!" each with a 1 paragraph blurb.

If you were the sort of teenager who was saving up for a computer to take to college - as I was - it provided endless opportunity to re-enter prices on spreadsheets while sighing over the latest unaffordable super-PC sporting a brand-new 80486DX-33 and 2 full megabytes of RAM.

<comment><USER3> In terms of "hours of 'entertainment' per dollar", the pre-ecommerce Computer Shopper exceeded all other media, second only to going through the white pages and making prank calls.

(There, I think I made enough "old person" references.)

<comment><USER4> Let me fix this up a bit:

Making prank calls from your neighbor's phone line with a beige box, wishing you had the money for a laptop with a built-in modem so you can use their line to dial up to NetZero and telnet to some stuff.

<comment><USER3> You're not helping. We spelled it "Telenet" back then[1], and we used kermit to get to it, but we mainly used it for UUCP.

My school was on BITNET, which really...bit. Laptops still required mains power supply. They were just portable. :-)

I'm going to hang a bloody onion on my damned belt now.

[1] I'm joking. They're different things.

</comment></comment></comment></comment><comment><USER5> _" Computer Shopper was like Vogue or Vanity Fair for nerds. You read it for the ads."_

Someone clearly has never opened up a Vanity Fair in his entire life.

<comment><USER6> Agree. Actually hard to believe that's not just a quick mistake given that "Alexis Madrigal is a senior editor at The Atlantic".

<comment><USER5> I looked up the author's bio to check which pronoun to use and also did a double take when I saw "senior editor at The Atlantic." I am hoping it is just a case of pandering to the nerd stereotype. The only other explanation is that Atlantic's online push has dramtically lowered the bar for quality.

I fondly remember going over each page of Computer Shopper before going to the Computer Fair to price out a new 486. But I also remember subscribing to VF so I could get my Christopher Hitchens fix.

<comment><USER7> I think, perhaps, you should read some of his other articles before making a judgement call on the Atlantic's quality or Alexis' qualifications.

[http://www.theatlantic.com/technology/archive/2012/11/when-t...](http://www.theatlantic.com/technology/archive/2012/11/when- the-nerds-go-marching-in/265325/)

<comment><USER5> A decrease in quality was one of the possible explanations. The other was that he is just pandering to the nerds. That is a great article, but it still does not change the fact that I expect people in the publishing business to have a more informed opinion than "people just read VF for the ads." However if you want to make it a debate about the quality of Alexis' writings all I can say is that he is no Christopher Hitchens or Michael Lewis.

</comment></comment></comment></comment></comment><comment><USER8> I too liked Computer Shopper for both the ads and the articles. All of the BASIC Stamp articles were quite the thorough treatise on the capabilities of that small system.

But what I miss is the openness. I've got the databook from Western Digital that let me write a BIOS for CP/M for the Cromemco series machines, it told me everything I needed to know to exercise every feature of their chip. Today, due to a combination of licensing and just sheer complexity issues such data sheets have largely faded away. I've been playing around with some of the ST Micro ARM chips and to really "get" them you have to have the ST Micro Data sheet, the ARM Cortex-Mx TRM, and the ARM7-M TRM. That is a ton of information about a chip with millions of transistors. Its just hard to put all of that into an accessible space. Even the lowly Microchip PIC or ATmega parts have fairly large datasheets associated with them compared to say the Z80 data sheet.

The most annoying though are the interconnects. You could easily get all the bus specs for the original IBM PC, but getting all the USB specs for a modern one? Harder and harder.

I really dislike the pervasive sense that I, as a developer, need to pay some tribute to the manufacturer before they will "allow" me to develop things with their product. Its not a general case thing, Atmel is pretty good about telling you anything you want to know for example, but every time I run into it, it leaves a very bad taste in my mouth.

<comment><USER9> > Even the lowly Microchip PIC or ATmega parts have fairly large datasheets > associated with them compared to say the Z80 data sheet.

And oh what you could do with a Z80 or a 6502, a few kilobytes of RAM and a couple support chips!

</comment></comment><comment><USER10> I miss the days of the 1" thick Computer Shopper. I remember lusting over ads featuring 3,000 Mb hard drives that cost something like $2-3K each and thinking "man...if I could only have one for my BBS". I remember the ZyXEL modem ads and how happy I was when I finally got the U-1496+ for Christmas and could start pulling my FidoNET mail down at 19,200 bps. Who could forget the Viewsonic ads with the "simulated" screen image of the Gouldian finches and thinking, "Damn...17" monitor...unreal!"

</comment><comment><USER11> Computer Shopper is still somewhat nostalgic for me, but I quickly lost interest after discovering pricewatch.com: [http://wayback.archive.org/web/19970209004411/http://www.pri...](http://wayback.archive.org/web/19970209004411/http://www.pricewatch.com/) I was in my 20s, but pricing and building K6 or 300A machines with Voodoo2s or FireGL cards for Unreal and Lightwave takes me back.

<comment><USER12> Same experience for me -- I couldn't justify buying Computer Shopper when pricewatch.com was far more timely. I did enjoy the column with Alice and Bob and that kept me buying it for a little while longer.

<comment><USER13> PriceWatch was a late entry into the game. (1995)

</comment></comment></comment><comment><USER2> Oh, important point. "Computer Shopper" in the US is not even the same type of thing as the same-named magazine in the UK. US: articles from Steven J Vaughan-Nichols. UK: articles from Charles Stross. SJVN now reports on open- source stuff for ZDnet, and Stross writes SF. Both are occasionally seen on HN.

</comment><comment><USER14> I'd think of Byte, Creative Computing, or even early Wired as more of a Vanity Fair for nerds than Computer Shopper.

<comment><USER3> Byte is a good comparison. There were ads and then there were ads hidden as articles.

<comment><USER14> In the later years of Byte? In the early years ('70s, '80s) it wasn't really like that (the way I recall, anyway!).

</comment></comment></comment><comment><USER15> The guy's talking absolute hogwash about reading it for the ads. Yes, some of them had nice stuff, but the there were a load of great columns and a young me read most of them, learning a whole load. I still probably have a bunch of paper clippings somewhere!

</comment><comment><USER16> If only someone had saved these for future generations :) [https://archive.org/details/computer_shopper](https://archive.org/details/computer_shopper)</comment>