Ember.js is driving me crazy
softwaresimply.blogspot.com
softwaresimply.blogspot.com
SOURCE CONTROL, DO YOU SPEAK IT?
In all seriousness, this is a major peeve of mine - the time that you're most confident that code can be deleted is when you're removing the pieces that depend on it. If the deletion really turns out to be wrong, you should be able to restore the code from source control. If you can't, stop using broken source control.
Leaving leftover dreck in your source files "just in case" is like stashing your leftover sandwich crumbs in your pocket at lunch. Clean up your mess!
There's also the mental cost of navigating among all that commented code every single time you need to read that piece of source.
In the event it is needed to be glanced at or restored, but you're exaggerating how problematic commenting a method out of code is. If I'm scrolling through code and see a commented out method my brain says "well that's not in use" and I move forward.
If a commented method stays in code for a few months I would complain or simply remove it myself, but it isn't hurting anything (unless in the case of Ember).
I can't think of any reason to do it that isn't a half-assed attempt at something a good source control system does much better. If you have lightweight branches, blame, and logs you can search and check by date, along with good changeset comments, then you already have everything your commented-out code can do, and all in the same place and system, instead of spread out into several different systems.
As far as Ember's issue, we didn't see the actual code. There's almost certainly a misplaced pointer somewhere. The author made of not being a JS regular, my guess: missing `var` somewhere.
However, commented out code is by definition free to be deleted by anybody else if it happen to be forgotten later on.
You may also want to check out FUSE (http://en.wikipedia.org/wiki/Filesystem_in_Userspace). Something on top of git may already exist. If not, it wouldn't be too difficult to create something like that.
That's the goal. Your top of mind is very limited; use tools like version control to help you conserve it.
> Also, it will require more work to bring back later.
Then you need better version control. You can either grab the reverse diff from the commit removing it and apply that (possibly with conflict resolution against more recent changes), or just grab the original file and copy the block of code out of it.
Ever.
Just delete it, you commented out code leaving scum. We all hate you. And you smell.
But seriously. Never commit commented out code. It's a cardinal sin and massive code smell. Never leave YAGNI, but maybe one day, hooks in code. Just delete it. It will never make it live and when someone actually comes to do that feature they'll usually half finish the feature before they even find your code, and then won't be 100% sure your code is supposed to do exactly the same feature and so they won't delete your cruft as they don't really know what on earth it's supposed to do.
And on top of that your code won't work because it hasn't been refactored along with all the live code, so all the property names are wrong, it references methods with signatures that have changed and probably even the names of the classes have changed.
Seriously, though, we do it all the time. Successfully. We even write skeleton code, and have other people finish it off, or take the half-baked idea and implement it properly. Sometimes in this sprint, sometimes in the next. We tend not to let these things stagnate though, so if the spec changes, the ideas are usually ripped out along with them. A lot of the cruft eventually comes out during code reviews...
It's definitely an anti-pattern, using one's code base to communicate....but the right team with the right processes, can work for the short-term. (short-term vs long-term is probably the key here)
Seeing a commented block scroll by doesn't waste top of mind. And if you really don't want to see it editors have something called code folding.
> Then you need better version control.
Have you ever tried searching a version history with thousands of commits to find a piece of code that you think you might have written awhile back, but you can't remember enough details about to come up with a good search term? No matter how good your version control is that's going to be a tough proposition.
I find that a `author(..) and file(..)` (hg) query gets you at least 90% of the way there if you have things split into a reasonable number of files. From there, running through a few guesses about search terms or even scanning the commit messages is pretty feasible. Date ranging can help, too.
There's so much data in source control - don't navigate by just commit messages.
But it did, that's not the problem the author encountered.
The issue wasn't that commented code caused a behavior change, it's that uncommented-but-assumed-unused code caused a behavior change. The only thing that got commented out was the markup that originally invoked said code.
Scrubbing back into history (or remembering that there's even something to scrub back to) doesn't seem to ever be as convenient for me as it is for people that are peeved by commented out code.
I'm not that great at Git, but I'm also not trawling through history very frequently and there still seems to be a mental overhead associated with it compared to seeing some commented code a few lines away.
The article goes on to say:
> I wasn't sure whether we would ultimately keep the
> widget or not, so I opted to keep the above
> javascript code for the controller and view around
> for awhile so it would be easily available if I
> later decided to re-enable that UI element.
That seems reasonable to me.In a file I was just working on before I decided to habitually check HN, I have two past versions of a function commented out above the final revision of the function. Next to each older revision, I've annotated some reasons why they were revised. When I continue to work on this function a week from now, I'm reminded of my efforts so far.
Someone would probably say that those annotations should be moved into commit messages and the git log should tell the story about this function.
But all that really seems to do is disperse my notes about this function across intermittent entries into this file's commit history. And once those past revisions are deleted from the current view of the file, I certainly won't remember that those notes exist for me to scrub back to in the first place.
- How do you manage this kind of stuff?
- What's your workflow for looking for and fetching deleted code?
VCS may need to grow a "full history" blame, which displays all hunks removed from the file.
So you're saying you're an Ember.js user, huh?
Ember, like most modern frameworks, represents itself as MVC. But it's more like MVCLCTMRA (model-view-controller-layout-component-template-mixin-router-application, if you're following along at home). There are just so many moving pieces, and there's a lot of overlap between them. Should I be using a layout, a view or a component here? They're ALMOST the same, and they don't always vary in the places you'd expect them to. Also, the "model" portion, ember-data, is fairly immature and doesn't seem to be anywhere near production-ready.
There are also some design decisions that just leave me baffled. If templates are supposed to be the ideal place to declare stuff, why does a view's root element have to be declared in a bunch of JavaScript properties instead? Why do some of their camel-case names (e.g. RESTAdapter) violate the (fairly strict) naming conventions they enforce in user land?
I don't hate Ember, and I'm sure it perfectly fits the mental schema of at least one person on the planet, but it doesn't click all that well for me. And it's abstract enough that I don't think working through problems in it is making me better at anything except Ember.
It's also probably worth mentioning that about 80% of the documentation online seems to be in the form of StackExchange posts, and about 80% of those are obsolete, as Ember has gone through a lot of radical changes in the not-too-distant past.
1) Layouts vs. Views vs. Components
A good place to start on this is the guides: http://emberjs.com/guides/views/adding-layouts-to-views/ http://emberjs.com/guides/views/ http://emberjs.com/guides/components/
From reading those, it should be pretty clear how layouts differ. I admit that it may be a bit less clear how views and components differ. Components are actually a more isolated type of view. Views have been around for longer, but in the future, we're going to discourage people creating custom view classes in favor of using components primarily. If you're not sure whether to use a view or a component, go with a component first.
2) Ember Data
Ember Data isn't a part of Ember Core, and for a good reason. While Ember Data is certainly a useable product (myself and many other do use it in production), it's not yet as mature as Ember Core (hence still being in beta). If Ember Data isn't good for you yet, you don't need to use it. Discourse is an example of a large Ember app that completely forgoes Ember Data.
3) Templates and Views
The template is rendered inside of the view's element which explains this. Alternatively, specify `tagName` as a property when using `{{view}}` or a component helper.
4) Documentation
The guides have a ton of information so you should definitely look there first. Also, if your company is really investing in Ember there are some good paid trainings available, including online courses. Tilde, my employer, has an online training (http://www.tilde.io/events/introduction-to-ember-online/) as does CodeSchool (who I do not work for) (https://www.codeschool.com/courses/warming-up-with-emberjs), among others. Since Ember has reached 1.0 a number of months ago, the API has stabilized and documentation will be valid for much longer.
Data persistence on the client is another area I feel hasn't been nailed down in general and thus can't support a lot of opinionated assumptions. Should data be persisted at all? Ember caches data from all requests to the server in a "store", but it's not clear how you keep that cache up-to-date. Perhaps you could use websockets to keep resources current but at the time I was using Ember there wasn't a clear, well supported way to do that. I think the jury is still out on whether we should be duplicating our schema on the front-end at all but Ember-Data has gone all-in on mimicking ActiveRecord. Again, the dust has not settled in a lot of areas of the front-end development world as far as I'm concerned so I don't feel comfortable with these decisions being made for me.
I tend to lean toward convention over configuration. On the server I'm a big Rails fan but I feel like it's solving problems that aren't moving targets. On the front end I prefer Angular because it solves the main headaches (two-way binding, testability, modularity) of front-end development without being too opinionated about the stuff we haven't reached consensus on.
As far as Ember Data goes, this is something that it's clear that a lot of people do indeed want. That said, you can use Ember perfectly well without Ember Data (see Discourse for example).
It's funny that you point to Rails as an example of consensus, because when you look at the server-side development community as a whole, there is certainly not consensus that the Rails way is correct. I wouldn't expect complete consensus on the client side any more than I would expect complete consensus on the server side. Rails (and others) have shown that you can have multiple healthy ecosystems each with their own points of consensus.
You're right about ember-data being optional but I mentioned it because it's what we were using on the project I was on.
I guess what I meant when mentioning rails was that there's a lot less change happening on the server-side than on the client-side these days so it's easier to confidently build an opinionated framework there. It's hard to favor convention over configuration when the very platforms you're targeting don't have established, agreed upon conventions.
Every time I've used multiple decoupled libraries instead of one large framework, things have gone fine. If a particular library isn't working out, I just swap it out for an alternative (or roll my own, if worst comes to worst) and continue building.
Every time I've used a large framework, I've ended up with major buyer's remorse. There's always at least one particular piece (like routing in your case) that's a bad fit, but everything is so tightly coupled, I can't just swap out the offending component without causing problems elsewhere...so I often end up accepting a bad fit.
For me, the productivity gains of big frameworks have always been outweighed by drawbacks as soon as I hit nonstandard use cases. I always find myself wishing I'd used multiple smaller, decoupled libraries instead.
I moved from Ember to React, and it has been a joy. It does what I actually want: makes interfaces easier to develop, lets you build your interface by composing parts together, lets you write view functions that are as smart as you are (no crippled templates like Ember/Ng). It is basically a simple low level building block that makes a lot of other stuff easier.
Anyway, as a non-genius developer who nonetheless has written a lot of javascript, React is my strong preference. Their approach is beautiful and simple.
For models, I've just rolled my own so far. I've experimented in one small project with having a global state object that cotnains all application state data, and then just having domain fns that operate on that data. Inspired by the react people's descriptions of "flux" architecture. It felt really nice.
When using Ember, I got really confused by Ember's Ember Data vs. Ember Model vs. whatever conversation. Again, I just didn't really know what to do here, and I attribute it to my own shortcomings.
It's worth pointing out that the Ember core team has been approached by the React core team with the intent of unifying React's view layer with Ember's application state management, which is a major component of what Ember offers relative to other frameworks. If you haven't had to solve major problems with navigation, routing, complex nested async logic, etc., for the particular app you're trying to build, then it sounds like React would get you most of the way there, but even the React team themselves realize that for medium-large scale apps, React's only going to take you so far.
It looks to me like htmlbars is handlebars emitting DOM rather than string. In that case, I think it will be missing the benefits of React. Again, though, I obviously don't understand Ember well.
It's not ideal, but in the absence of a true type system, it's all about mitigating potential problem areas.
That said, there are differing opinions on which part you should "simplify" through a framework. Some of them are going to feel more magical than others. And when you come in with preconceptions about what makes a good environment, you're going to think about how the framework and environment lives up to your ideal. Some things you fix, some you leave as they are – and choosing the right battles is incredibly important. But service code and UI code are different sorts of warfare against complexity, I'd be skeptical of intuitions across the two domains. (None of which means Ember.js gets it right either – but if they don't, then I doubt the why is they just need a statically typed language.)
Spontaneously Changing Values: What was the key that you were trying to set? On what type of object (Route, View, Controller, etc.)? There are indeed some special values and it might be something that Ember can warn you of in the console as well as be documented. I'll be glad to make some documentation changes that make this issue easier to catch if you can provide me reproduction.
Godlike Refactoring: I work on a team with a widely distributed level of skills. One of my favorite features of Ember (which both has and will continue to save me hundreds of hours) is the fact that even if you make a mess of something you can generally come back and clean it up one piece at a time. My metaphorical description of this is that "all of the crap is in nice neat little piles instead of spread on the walls."
JavaScript.next: In the next/current version of JS both of these warts should be possible to resolve using Modules and Object.defineProperties(). I firmly believe that your complaints are not centered around Ember (which I honestly believe is insulating you from the worst of it) but instead from flaws in a language that was literally designed and built in an incredibly short time (my recollection is "a week" but I can't find a source).
(Edited for clarity based upon mixonic's reply.)
But regardless, Ember will not load everything in the App. namespace blindly- it will wait until that item is required, then try to load it.
This is your helpful Ember #protip for the day. :-p
That being said, now that you mention it, it seems far more likely that the issue was HTML vs HBS commenting. As an aside, what is the default behavior going to be for HTML comments inside of HTMLBars templates? That seems like a really weird edge case to decide how to handle (for developers).
And yeah, I'm unsure of that the behavior will be in HTMLBars. I really hope it doesn't touch logic inside HTML comments- that would be quite nice.
Anyway, for future reference, you may want to learn how to use the JS debugger (both Chrome and Firefox are quite good). You could have set a break/watchpoint on the variable 'foo'. Once it has changed, you can inspect the stack and would have found that the set('bar', ...) method was involved. Should be much quicker than printf-debugging...
Your debugger should be able to display the corresponding .js file for each line in the call stack. Jump down the stack until you find your code.
Yes, it doesn't solve the problem (wanna talk about debugging freaking JSP or TinyMCE plugins? :p) but you won't
> spent the better part of a day trying to track down the source of this problem.
We are actually working close with the firefox and chrome teams, to drastically improved general JavaScript developer ergonomics when debugging.
I mostly work in compiled, statically typed languages, and it can be a bit of a surprise in Javascript when you don't find out about a syntax error until execution just stops, half way through your application loading, because of some code in a function you didn't think was called.
It's a surprise. But that doesn't mean it's wrong. We just aren't using the right tools - unit tests, JSLint, etc.
Question to regular JS users - what do you do 'in place' of static checking?
Sticking to some kind of style guide also helps. Idiomatic.js is a good starting point.
Also, doing some basic checking on your own is often a good idea. Look at your arguments, make sure they're what you expect, and if now, throw an error. That'll make it a bit easier to see where your problems are, since you won't have to dig around stack traces as much.
I don't think anyone's doing anything 'in place' of static type checking exactly. Oftentimes I'll check if a method exists on an object before calling it. Usually when I'm "type checking" I really just want to know if an object has a certain attribute. That gives a fair amount of flexibility because polymorphism is built in.
I think by and large the errors that would be compile-time errors in a statically typed language are caught with unit tests (I use mocha). For front-end work, end-to-end testing has also gotten quite good and easy. Take a look at karma if you're interested in a good front-end testing workflow.
JavaScript is hard, it's a very loose language and it's implementation in browsers sets you up for all sorts of falls. If you're going to code using it you either need to be disciplined or understand it intimately, preferably both. The problems in the article were not caused by Ember.js
Is it really fair to blame this on dynamic typing? Having setters with side effects seems like a design decision to me, and not one that is easily supported. I would be interested in hearing an explanation of why this behavior is javascript's fault.
Those "set" and "get" calls are a great example: they're an unfortunately necessary workaround for Javascript's lack of real dynamic message dispatching (like Ruby's method_missing). We all look forward to ES6 fixing this.
The run loop is another example. It's a gross hack that wouldn't be necessary in a nicer language that managed its own runloop internally. Javascript developers who are ignorant of other paradigms often make the false claim that all the callback-driven asynchronicity is worth it because of performance, but they fail to realize that you can have exactly the same asynchronous architecture while writing code that reads synchronously.
The problems posted in the article are really hard to judge because the author doesn't actually explain what happened.
In the first example, he doesn't try. Fair enough, it's a judgement call on whether to spend time understanding what happened. Personally, I would consider it high priority, because otherwise you have no assurance that the same problem isn't biting you elsewhere.
In the second, he says something that doesn't actually make sense: "Ember's set function has special behavior for values in the content field". I know Ember's source about as a well as anybody not in the core team, and that statement isn't even false. If I had to guess, I'd assume he's really saying something about how ObjectControllers behave as proxies for models.
I don't mean to write off whatever problems he encoutered -- they are clearly real problems, either bugs in Ember or failures of developer ergonomics. If he could point to the specific actual problems I would personally work on a patch to address them. But I don't have enough to go on.
I do agree on the callback thing though and I find it kind of sad that not many people use CPS compilers for JS even though things like Cofeescript and SASS are pretty common.
It comes down to lack of mature tooling and debugability: coffeescript is easy to debug, because it's a very light level of syntactic sugar and dropping into the Javascript is easy. A more aggressive compilation step would require me to put a lot more trust in the maturity of the compiler and associated tools.
I'd be happy to help you track down the issues you came across and explain to you what is going on.
You can reach out on Freenode or Twitter, I'm @ebryn. Otherwise, email me at erik.bryn -at- gmail.
It can, occasionally, be frustrating (for example run loop craziness), but in my opinion it's no more frustrating than working with any other stateful front end framework (WPF, backbone etc...).
But the whole leap to needing "strong static type system like Haskell" leap seems really random.
It seems more like a need to spend more time with JS (which can be weird and a pain, but eventually makes sense) than blame Ember, which is pretty complex on top of the various aspects of JS that are a bit unintuitive to start with.
Also the whole static typing reasoning is BS, because the author could have simply used either Google Closure Compiler Linter that can enforce typehints, TypeScript or Dart.
In the second case, he used HTML comments to comment out Handlebars code, not realizing that he should have used Handlebars comments.
In the second case, it seems quite reasonable to assume it knows about HTML comments and that they would behave as I expect.
http://emberjs.com/api/classes/Ember.ObjectController.html http://emberjs.com/api/classes/Ember.ObjectProxy.html
Sorry to hear about the pain points so far. I felt like this many times when I was starting with Ember. It definitely gets better the more you become familiar with all the different conventions.