Sunday, March 18, 2018

Runtime Error: Cannot find module 'foobar.d.ts' from Typescript

Continuing on with the theme of me using my illustrious blog as a dumping ground:

This runtime error puzzled me. It compiled cleanly in Typescript, but at runtime raised an error. It shouldn't have even been compiled in the first place. So what's the deal?

`Error: Cannot find module '../../../typings/foobar'`

Well, the deal is pretty simple. The typing file contained an enum data structure. Since those get converted to actual code, that meant that the compiler emitted a 'require' statement for the type definition file, which meant that Node tried to load it... can't load a d.ts file at runtime, can you?

Wednesday, February 07, 2018

"Something seriously went wrong: Invalid Parameter" for XPS 13 9360?

I just had a simple Ubuntu update soft-brick an entire laptop. My less-than-two-years-old XPS 13 9360, to be exact.

The error message was,

Something seriously went wrong: Invalid Parameter
Shim was unable to measure state into TPM

Ironically I had spent the ten minutes earlier ranting to myself about how much I hated having to use macOS.

Here's how I recovered the system.

You'll need:


  1. A USB stick, formatted as FAT32

Either go here or google "XPS 13 9360 bios update". 

Scan the list of downloads for an entry that says "System BIOS" (you may have to click "View More" to see the entire list). Download it. The version I got was 2.4.2, but your mileage may vary. You'll only find an .exe file to download: that's fine. Take it and put it on your USB stick.

Plug the USB stick into the affected laptop. 

Restart the laptop, and jam F12 as frantically as possible. Eventually you'll go into the bios boot menu. Uses the cursor keys to highlight the "Bios UPGRADE" entry, then press ENTER on your keyboard.

Click the "..." button on the next page, and then click the empty dropdown. You'll see entries like "F1, F2, F3", etc. Go through them all until you find the .exe you downloaded earlier. Select it, and press the open button near the bottom of the dialog.

Wait a second. If everything went correctly, the system will recognize the .exe file as a bios update. Press the "install" button, then sit back and relax. Maybe keep your animals away from the laptop, because this isn't something you'll want them to interrupt with their big stupid cat feet.

The computer will automatically reboot. If all went well, you'll be staring at your login screen again. If you sign in and are just staring at your default wallpaper, without a GUI in sight, do this:

  1. CTRL+ALT+F2
  2. Log in with your username (I hope you remember that), then type in the following commands minus the quotation marks
  3. "sudo apt-get update"
  4. "sudo apt-get upgrade" (this will not upgrade your distribution to Ubuntu x.x, it'll just grab whatever new updates there are for your current distribution. If all that sounded greek to you, don't worry about it.)
  5. "sudo shutdown -r now"
Your computer should reboot after that last command. Now, when you log in, you should be staring at your old trusty desktop... I hope. If it's still broken, then I can't help you, but Dell probably can. Your service tag is under your laptop. Good luck, my friend.


Friday, December 15, 2017

My 2017 Upwork experience in a nutshell

Disclosure: haven't used account in a year because the site's been trending towards general uselessness and none of my existing clients were pleased and future clients simply wanted to avoid the site due to the rising expenses.

> don't use site for a year because existing clients are pissed off at it, future clients are just like LOL no
> get email in Q1 saying that my account is "needs" video call verification.
> had billed over 300k in the 3-4 years i was super-active there, haven't used site since 2016, need to video chat for what exactly??
> get three more emails like this, ignore them all
> get a fourth and open it because i'm not paying attention to what i'm doing
> inside is implication they "may" reverse the last payment transaction they made **over a year ago** if i don't comply
> seriously think about letting them do it (the last transaction was a pittance) and making a fight out of it
> too lazy, succumb to video call
> suddenly dogs
> holy shit dogs
> person on other end must be working in the back office of a vet there's so many dogs barking
> can't hear most of conversation
> suddenly random programming question about a technology i haven't used in like 3 years
> ??
> give quasi-correct answer that i would have normally googled first for complete correctness.
> call end
> goodbye dogs
> you were good dogs

Upwork is so fucking weird.

I do miss oDesk as a platform. They were pretty focused on connecting me with clients and then getting out of the way. Upwork is just trying to sell me membership plans and their bizarre interview currency and all this other random garbage that looks like its been pulled from the playbook of a mobile game.

After taking a quick glance at the current marketplace, I get the feeling that whatever new-age fuckery Upwork has been up to has had a negative impact on solo high-level freelancers.

Not sure I'd sign up for a new account in 2017, but your mileage may vary.

Friday, September 11, 2015

Hello, Typescript!

After spending some time wrestling with it, a few months ago I began porting my Dart-based codebases to Typescript. I can't say the process has been particularly easy, but ultimately it's been worth it.

The tools

The roughest part of the migrations, I think, was dealing with the current JS ecosystem. In Dart, everything is pretty straightforward -- if you need a pub package, use `pub`. If you need to format your code, use `dartfmt`. Do you need to build for the web? `pub build`. If you're writing code for the server, it looks exactly like code for the client, except you switch out different libraries.

While the ecosystem has finally consolidated around npm for packaging (sorry, bower), there's still some issues:

  • If you're targeting the browser, should use webpack or browserify? It's a hard question to answer: they're _very_ similar, with the exception of a few things here or there.
  • If you're targeting io.js, do you use the built-in ES6 support, or do you go balls to the wall and use every ES6 feature _now_ and just compile down to ES5 with Babel?
  • Modules: CommonJS? SystemJS + JSPM?

There's no clear standout: it's more like you have two mediocre solutions to pick between, with only your gut instinct to go on. This is probably more an issue of maturity: in time, just like Grunt v. Gulp, an overwhelmingly better option will appear.

Typescript

Getting into Typescript isn't very straight-forward, either. For type definitions for external libraries, you're going to rely on DefinitelyTyped: a massive, massive repository that Github won't even display the entirety of online. In order to better finagle it, there is an npm module called `tsd` that installs a command line that will quickly find and download type definitions for you.

Then there's your `.tsconfig` file, which configures a TypeScript project, and has to be created by hand if you're not using atom-typescript (hint: use atom-typescript). 

There's not a lot of documentation on typical Typescript applications.

  • What directory _should_ your *.ts files go in? lib? src? scripts? I've seen them all.
  • Type definition files: do you check them into the repo? Yes? No? If no, how do you handle custom type definition files?
  • Should you check in the generated *.js files? They're build artifacts, but also required for the application to run after checkout.

After those hurdles, though, things get a bit easier. Typescript, as a language, is great to work with; its obvious and its type syntax is very concise. It'll give you all of the ES6 features you hoped and dreamed for, as well as typing for analysis. On top of that, I think they're working on await/async support in 1.7.

I'll say this, though: I would have really appreciated comprehensive "Getting started with Typescript on io.js" and "Getting started on Typescript on the browser" guides. That's one of the things Dart does right: guides so you can hit the ground running right from the start.

But Arron, [vague reason why I should still be using Dart]!

When I first started using Dart in 2013, it was pretty great. I didn't like the language all that much, felt too much like a random and wordy hodgepodge of other languages, but everything else about it was incredibly awesome...

...in comparison to the state of 2013 web development.

Back then, Typescript was buggy, it was still Grunt vs Gulp, browserify wasn't stable yet (I think?), yadda yadda yadda, Polymer wasn't even born yet, and angular 1.x was still had a bunch of people trying to figure out the difference between a service and a factory and a provider.

So I deployed some production applications with Dart, and everything was good, for a while. Then these things happened:

1.) Clients started asking for features and integration with third party components.
2.) Heavier usage, exposing the flaw of dart2js when it comes to tracking bugs.

#1 is the thing every bitches about the most when they start using Dart: awful javascript interop. Basically you write _tons_ of proxy objects to hide how ugly `dart:js` is, or you go raw and spend your time building against the `dart:js` library directly. Both are a massive timesink, and both are hideous.

Clients don't care about either of those. There's already a JavaScript version available, why can't you just drop in a file and go to work?

Why can't I, indeed.

#2 was a sucker-punch I didn't quite see coming. When you're building an application Dart, you normally use Dartium to run the code. Dartium has a DartVM embedded inside of it. The stacktraces are pretty clear when something goes wrong. There's also good IDE integration (Dart Editor at the time, WebStorm afterward).

But when you take a Dart application to production, it gets compiled down to minified JavaScript, and when it causes a stacktrace in a browser, the data that gets reported by your error tracking service is a nightmare to go through.

Here's an example from a Dart plugin for Atom (which is awesome, by the way): https://github.com/dart-atom/dartlang/issues/277

 At /home/robert/.atom/packages/dartlang/web/entry.dart.js:15723  
 Uncaught Error: NullError: method not found: 'get$iterator' on null  
 Stack Trace:  
 TypeError: Cannot read property 'get$iterator' of null  
   at [object Object].J.get$iterator$ax (/home/robert/.atom/packages/dartlang/web/entry.dart.js:40600:41)  
   at OutlineView.dart.OutlineView._handleOutline$1 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:23413:23)  
   at [object Object]. (/home/robert/.atom/packages/dartlang/web/entry.dart.js:16917:32)  
   at _RootZone.dart._RootZone.runUnaryGuarded$2 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:30734:20)  
   at _BroadcastSubscription.dart._BufferingStreamSubscription._sendData$1 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:29878:20)  
   at _DelayedData.dart._DelayedData.perform$1 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:30072:18)  
   at _StreamImplEvents.dart._StreamImplEvents.handleNext$1 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:30145:16)  
   at _PendingEvents_schedule_closure.dart._PendingEvents_schedule_closure.call$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:30120:12)  
   at _AsyncCallbackEntry.dart._AsyncCallbackEntry.callback$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:29023:30)  
   at [object Object].dart._microtaskLoop (/home/robert/.atom/packages/dartlang/web/entry.dart.js:27728:12)  
   at [object Object].dart.wrapException (/home/robert/.atom/packages/dartlang/web/entry.dart.js:16669:17)  
   at _rootHandleUncaughtError_closure.dart._rootHandleUncaughtError_closure.call$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:30703:17)  
   at _AsyncCallbackEntry.dart._AsyncCallbackEntry.callback$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:29023:30)  
   at [object Object].dart._microtaskLoop (/home/robert/.atom/packages/dartlang/web/entry.dart.js:27728:12)  
   at [object Object].dart._microtaskLoopEntry (/home/robert/.atom/packages/dartlang/web/entry.dart.js:27734:11)  
   at TimerImpl_internalCallback0.dart.TimerImpl_internalCallback0.call$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:16100:35)  
   at invokeClosure_closure.dart.invokeClosure_closure.call$0 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:17775:41)  
   at _IsolateContext.dart._IsolateContext.eval$1 (/home/robert/.atom/packages/dartlang/web/entry.dart.js:15714:25)  
   at [object Object].dart._callInIsolate (/home/robert/.atom/packages/dartlang/web/entry.dart.js:15354:28)  
   at dart.invokeClosure (/home/robert/.atom/packages/dartlang/web/entry.dart.js:16817:18)  

The saving grace, in my production use of Dart, was that I had written all the code, so based on a stacktrace I could reasonably determine the general area that caused it. But imagine if I had a team of two or three developers alongside me?

Over time the advantages of using Dart dwindled. I'm not a dogmatic dude; I don't have any philosophical objections to Javascript, nor am I morally opposed to it because it's the spawn of Satan. 

It's just an awkward language with an awkward ecosystem that's still growing up.

And, right now, when I compare Dart to Javascript / Typescript, I don't see as many compelling reasons to use Dart anymore.  Really, the only things I'm missing from the language itself is a sane `this` semantic (yes yes, I know about function binding) and async/await, and the former is coming down the pipe via Typescript soon.

I still keep tabs on Dart, though. `dev_compiler` might be good for the community, and it seems like they're discussing pretty interesting language changes that might make Dart itself more palatable (dropping new, non nullable by default, RHS types).

Lessons Learned


Being backed by a corporation doesn't mean jack when it comes to programming or programmers. 


A healthy ecosystem is created by producers. 

An ecosystem of consumers is basically an impatient mob waiting for their corporate overlord to tell them what to do and how to do it, and by the way when will you be making the libraries for them to do it with?

Producers are the ones who make the cool shit that attracts consumers and other producers. They make Rails, Rack, Merb. Sometimes they're backed by a corporation, and sometimes they're just flying solo, but whatever the case, they're the ones that ultimately grow the ecosystem.

Dart doesn't have enough producers. There are a lot of promising pub packages that were abandoned early on after Dart went 1.0. I'm assuming Dart's familiar-to-a-fault syntax had something to do with that.

Prepare yourself for the anger, for it will flow freely.


I come from Ruby (C# before then, Java before that, C++ before that), and some things about ES5 still infuriate me.

No language is perfect. Learn to accept those flaws and mitigate them as best you can. And try not to think about the fact that setInterval accepts a function as its first parameter and not its last parameter.

Learn about FRP, and use bacon.js to do it.



FRP is awesome, and can simplify certain problems. I won't give you the salesman's pitch; check out the website and its examples, as well as tutorials, to get a better feel for how it might help you.


Language culture is almost as important as the language itself.


I like Kotlin. It is awesome. It has seamless interop with Java, while at the same time being incredibly concise and delightful to program in. 

That doesn't change the fact that when you do interop with Java, you still have to deal with, you know, Java. Not the language's syntax, but the result of that: ugly and bloated paradigms. If you're not careful, it's like an overweight boxer punching you in the face every time you try to get any work done.

It's 2015, and Javascript has a culture of being extremely straight-forward with code and its documentation, and that's awesome. 

That's it.


Sorry, felt like I needed another header just for the end. ¯\_(ツ)_/¯

Friday, October 17, 2014

What OS powers my developer machine?

Clients and friends know that for a long, long time I've used Linux as my primary development environment. There were a few years when I did .NET work, which required a Windows machine, but once I transitioned away from Microsoft's ecosystem it made no sense to work in an environment where your the cost of your developer tools and services start nearing the 4 digit range. (this was before BizSpark and DreamSpark or whatever Microsoft are calling their programs now a days).

I used to run Ubuntu back when it was on Gnome 2. When Unity came out, it was better than Gnome 2 by a long shot (anything was better than Gnome 2, honestly), but it was glitchy and annoying. Around that time I started dabbling with Gnome 3, and after a few weeks started running that hacked-up version of Gnome 3's "Gnome Shell" someone published to a PPA.

It was a blast. While it had its fair share of bugs, it was mostly stable and the design kept things out of my way, unlike Unity's schizophrenic global menu and obtrusive dock. Of course, as Ubuntu progressed, Canonical decided to do things their own way, and support for Gnome 3 became poorer and poorer -- first it was default Gnome 3 apps that were missing, then Gnome Online Accounts was MIA, and then Gnome 3 was stuck at some ancient version full of paper-cut style annoyances.

I think it was maybe a year ago or more when I decided to start clean with Fedora.

And let me tell you, a clean Gnome 3 install is night and day than what is (probably) still shipping with Ubuntu. I had no idea how much I was missing until I started using Fedora. It's been a good year -- but it's been a really annoying few months recently.

I can't remember where it started, but I had a need to download a program that offered a Linux version. So, fine, I'll just -- oh, it only offers a .deb. For Ubuntu.

And that's how it started. A few days later (maybe a week), I was out fishing for another pretty polished application that offered Linux support... except not really: it only offered me a .deb.

Now, I hate both rpms and debs. I'll take a binary .tar.gz any day of the week: I don't like giving random packages on the Internet sudo privileges. I've also seen what it takes to make an RPM and I'm not surprised that their first choice is going to be a deb file if they do any kind of package at all.

Anyway, my point is that once I started leaving the "safety" of Fedora's repositories I discovered that in the "real world" Linux support is actually Ubuntu support and damn everyone else. You can probably download the sources and compile everything yourself -- I did that with Atom for a long time -- but it's still a pain in the ass. Atom, by the way, recently offered support for Linux -- sorry, Ubuntu.

I don't want to run Ubuntu. I don't like Unity's interface. I don't want to deal with whatever frankenstein Gnome 3 they have going on. I am picky, and my days of fiddling with distributions is well behind me.

Gnome 3(.12), by the way, still needs a lot of love. Over the year on Fedora, I've had the following random problems:

* Computer seems to have frozen, but the monitors are off so I can't actually tell what happened. Can't wake the monitors up -- is the computer not outputting a video signal? Who knows.
* The login widget on the lock-screen just... disappears after I click it. Nothing but a slate-gray oasis awaits.
* Sometimes it freezes up. Sometimes. I'm not sure why. Or how.

I don't know how to even begin to reproduce these things, or what logs I should look at, or if it even matters to anyone but me.

Tonight, for the first time since I've had it (2+ years), my Macbook Pro froze. I held down the power button and restarted it. It told me that the computer had been restarted because there was a problem. It asked me if I wanted to start-up the programs I was running before the crash. I said OK. Everything was fine.

It works. Homebrew exists. Applications that are multi-platform run on it without an asterisk. The performance is stable.

I've been using it for my full-time dev work for about a month now. It's an experiment. So far I'm enjoying it.

It's not really one thing that's driving me from Linux distros, but really a multitude of things. Openshot crashes, a lot. Pitivi... ... I'm not even sure the people who develop Pitivi use it. Why is Audacity showing me all these audio inputs when none of them have anything plugged in? Why is all this crossplatform software flowing in from Windows and OS X not really crossplatform? Why is pretty much every open source driver blacklisted in Chrome's WebGL implementation?

There are things I find annoying about OS X -- it's shitty file manager is suspect #1 -- but everything else just works, and I'm OK with that. Hopefully in 3-5 years using RPM / Deb for applications will fall out of style, and a focus on usability will be present in the next generation of applications.

I only got the Macbook Pro because a client had an environment with a L2PT / IPSEC VPN that could only be successfully logged in via Windows / OS X. The bug was documented on some unattended BugZilla installation somewhere years ago. Of course the earnings from the contract was vastly larger than the infuriating sum is cost me to buy the Macbook, so it was a no brainer, but the entire time I kept thinking "I could have bought 2 really good laptops for this price."

I don't feel that way any longer.

But no quad-core Mac Minis? Fuck off with that bullshit, Apple.

Monday, April 14, 2014

e2e testing with AngularDart.

So this weekend I spent a grueling 12 hours trying to get an e2e test harness going for a personal project of mine I built in AngularDart.

I will spare you the obscenity-laden recap and share with you the minimal amount of code needed to get an e2e testing solution going using NodeJS.

Before you ask "why not Protractor?" let me explain: it doesn't work with AngularDart. I looked into the codebase and it relies on AngularJS's internals -- I had always assumed that AngularJS just emitted DOM events as the integration point for Protractor, but it turns out there's some private services in there like $browser that are accessed directly. Since I'm not using AngularJS, that immediately removes Protractor from the running.

If you don't know what e2e is, it stands for end-to-end testing. Basically, you can unit test the hell out of your codebase, but at some point you have to make sure that based on user interaction everything works in harmony. It catches problems in your markup like not sending the right message when a user clicks an element, and other integration issues.

I'm going to be sampling files straight from my repository, so the usual caveats apply: I am a foul-mouthed asshole and have no regrets about that, I might eat your baby, etc.

1.) First off, let's get some necessary packages installed:


jasmine-node: our test framework. This allows you to use Jasmine in Node, which is great, because Jasmine is great.

coffee-script: CoffeeScript makes for very fluent, very readable test code. Your mileage my vary, but I use CoffeeScript where-ever I'd normally use JavaScript.

webdriverjs: this is our API for interacting with Selenium. Despite the name, it is not the official Selenium WebDriverJS package; it is a more fluent, node-like API. It's got some minor issues: failures from Selenium don't bubble up, so you have to check the Selenium output to see what went wrong, and why.

selenium-standalone: this package gets selenium server and has a helper executable that starts running the Selenium Standalone Server, which is required. It comes with Chrome driver.

gulp: task runner. It's simple but undocumented; I will probably be migrating to Grunt in the near future. Dart has 'Hop' but that seems just as bare documentation-wise, and it's also more complicated to get going with.

Running `npm install` (and optionally `npm install -g` so the executables packaged with those packages are available globally) gets us ready.

2.) Now let's setup our Gulpfile. Typing 'jasmine-node spec/' gets pretty tiresome after awhile.




Nothing too complicated, just some tasks to run tests. I prefer CoffeeScript, so Gulpfile.js just executes the CoffeeScript version of a Gulpfile.

Just typing `gulp` in the terminal will start executing all of our specs. I keep my specs in the subdirectory 'spec/' instead of 'test/' because why not.

Now, since this ended up being a total nightmare to get going -- I went through three or four more high-level APIs before I discovered what exactly was going wrong -- I ended up writing some "sanity checks." Here they are:




Typing 'gulp selenium' in one terminal, and then 'gulp' in another should result in 2 passing tests.

Great! Now let's setup a basic config.coffee file to store our settings for an actual, but extremely simple, e2e test for our app. I'm not promising anything about the accuracy of the comments in this file.



The timeout is super large because it takes `pub serve` forever and a day to compile an AngularDart application, and I'm still not sure if that has any influence on how long webdriverjs / Selenium waits until it tries to interact with a page.

Now I wrote a small 'sanity check' test for the application itself, which basically ensured that the page loads properly:



This test just ensure that the page actually loads in the browser.

You'll need to run `pub serve` first. The first time I ran this test it took about 60 seconds for dart2js to finish compiling on a Macbook Pro.



Here is the test that gave me the most trouble: it's where I exercised the Selenium drivers beyond a simple sanity check and encountered the dozens of problems that had me pulling my hair out.

Chrome wouldn't find any elements on the page, Safari worked fine (I discovered by accident) except that the webdriver won't interact with file inputs properly, Firefox crapped out with a bug in the shadow-dom polyfill, and PhantomJS was just... I don't know, there were too many errors with PhantomJS for me to even bother with.

In the end, to get this test passing, I choose Firefox as the browser and commented out the shadow dom poly fill ("shadow_dim.min.js" in your AngularDart index.html file, probably), which caused some rendering errors but otherwise allowed the functional parts of the test to pass... but only in Firefox. I also removed some expected user behaviors and jumped straight to populating the file input.

You'll notice I have some helper jQuery statements: normally in your stylish app, the file input is hidden. You trigger it when the user clicks on another element, like a button labeled "Upload File."

However, you can't do that in Selenium. Since it's running a real browser, clicking on "Upload File" blocks the process since the OS then presents its file picker dialog. So what you have to do is use Selenium's API (webdriverjs calls this 'chooseFile'), which then simulates the process of attaching a file via a file input.

Of course, since your stylish application has hidden the default ugly file input, there's nothing for Selenium to "click" on, so the `showInputs` makes the element visible for testing purposes.

Is the `selectFile` script necessary? I don't know. It was there when I finally got everything working, and after 12 hours of hacking away trying to get a basic e2e test going it was 3AM and I wasn't about to try messing with it right then.

Anyway, that's what I learned about e2e testing AngulartDart applications.

Sunday, March 16, 2014

And the winner is...

Recently, I evaluated some modern tools to build an SPA (single page application).

The forerunners were Dart + AngularDart, or Dart + Polymer.dart.

In the end, though, I actually went with AngularJS, which wasn't even on the original list.

The major knocks against Dart + {AngularDart,Polymer.dart} was simply that they both enforced use ShadowDOM. Polymer had recently taken out "applyAuthorStyles" as well as the "lightdom" attribute, and AngularDart's templates are based on ShadowDOM.

While that's fine for some hobbyist stuff I might do with Dart, I am definitely not interested in playing with ShadowDOM when I'm trying to quickly iterate an application. I don't have the resources to constantly reinvent components  -- Bootstrap, for instance -- at every step of the process.

I understand the uses of ShadowDOM, but they just don't apply to most of the work I do. I'm not building generic widgets for everyone to use across the web, I'm building them out specifically for a particular application. Maybe they're generic enough they can get slurped out -- fine. But at the time of me writing them, I'm interested in getting them working as quickly as possible.

If I had a dedicated designer who would do all the work of crafting everything from scratch, I may have been more inclined to pick AngularDart... but then I would just be moving the burden to them instead. Either way it's still an unnecessary use of resources, especially in 2014, when you can cobble 50% of your webapp together with off the shelf components.

I suppose I could have just used "regular" Dart and some additives, but I'd be pretty unproductive, and in the end I would have something that looks like a bastard child between Angular + whatever, with nothing to show for it other than a lot of wasted time[1].

My days of reinventing the wheel were over years ago.

All that said, AngularJS has turned out to be very nice! I originally started with plain old JavaScript, but recently transitioned to CoffeeScript; productivity has improved significantly and the code is much more readable.

I've never had a problem with debugging the generated JavaScript in DevTools or Firebug, which is a complaint I hear alot about CoffeeScript. I suspect a really old versions of CoffeeScript produced some hard to read JavaScript, and that  the meme still lives because, well, this is the Web and nothing really dies here.

[1]: A project I once worked on was based off Sinatra instead of Rails because the team lead said it was "lighter." I looked at the codebase and it was basically a bastardized version of Rails: they pulled in most of the active* gems, and had half-assed "url_for" constructs that looked similar to their Rails counter-part but functioned completely different in certain ways. Developing against that codebase took forever. In some down time, I prototyped porting it to Rails proper, and it was about as fast as the Sinatra version...