We (madebysofa.com) are using it for an upcoming product. The most important lessons we learned are:
- We can really bring near-desktop-class-user-experience to the web, and that's amazing.
- Cocoa programmers pick it up fast. In our case a week or so, and one more for all the tools around it (press, nib2cib).
- Some stuff is missing/broken in the framework, but you can look at the source and fix it! We're not used to that with regular Cocoa where we have to basically guess what is happening inside.
I'm using it for my current project, currently ~6k semicolons.
Stream of thought time! Forgive the sloppy writing, which will be full of interjections.
Obj-J is more verbose than regular JavaScript. More use of objects and method selectors than callback functions. I usually prefer callbacks to delegate objects. It's easy to just make a catch-all object and use that with an anonymous function if you'd rather not specify a class for something that requires a delegate method, though it's not idiomatic Cappuccino/Cocoa.
Cappuccino is almost identical to Cocoa. If you have experience with Cocoa you can just switch off the part of your brain that wonders how you should be doing something and just do it like you would have with Cocoa, and it'll just work, as they say. Not terribly exciting, but it works – and frighteningly well. I spent over a month working on my app, testing exclusively in WebKit and Firefox. Lots of what would be called advanced behavior "for a browser app" (but nothing that would be called advanced for a desktop app from 5 years ago) and making it work in IE required just a few tweaks, most of which were unrelated to Cappuccino (comet longpolling library I was using, Orbited.)
Good stuff:
Awesome, responsive, feels-right GUI stuff. Can't break objects by clicking and dragging around. No weird jumping around behavior. Stuff doesn't get dislodged, misaligned, etc.
Don't have to work with the DOM. At all. This is a huge deal if you have a background in desktop GUI stuff – if all you've ever used is the DOM you have no idea what you're missing. It's pretty terrible for anything except vertically scrolling pages of text. Working with the DOM was like having someone beat on your shins with a baseball bat. "No I want the box to go there. There! THERE! ARGHOSOIJSD"
Built-in serialization for Cappuccino classes. Canvas/vector abstractions. GUI building in Apple's Interface Builder. IE, WebKit, Opera, Firefox all work from the same code without apologies. Much more finessed event handling.
Bad stuff:
Awful debugging. Worse than regular JS debugging. Usually can't even easily tell what line a syntax error is on.
Still has tons of stupid JS problems – implicit globals, type coercion everywhere (with JS primitives), slow as molasses.
About a 10% performance hit on tight loops if you use Obj-J message sending in them.
Mostly non-existent documentation. Still in rapid development, things change a lot. If you don't already know how to use Cocoa, expect to be totally lost.
Other stuff:
Has its own event loop. Allows for more flexibility than only DOM events, but it might cause problems if you use other JS code that uses events.
Building Cappuccino in Linux had a few hiccups, but I got it working (they were related to Ruby 1.9.) Just Works in OS X without any tweaking necessary.
Best reason to use it: Cocoa is not perfect by any measure, but we know it works for GUI apps. Cappuccino is like Cocoa; it works.
A lot of effort has gone into Cappuccino. Behind the scenes, a lot is going on to maintain the transparent layer of browser compatibility that you get to work with. There are warts and issues, but you can absolutely build something with it right now and it will work.
A lot of good points. About debugging, I would strongly strongly disagree.
The Safari 4 / WebKit debugger is actually getting quite good. Add on top of that the profiler and support for native method names we added to WebKit, and you've got what I consider the best debugging environment in any browser.
Break on exception works well, and even though you are seeing post-processed code, it looks nearly identical to the original.
(The parse error problem is just a generic Safari problem, and Firefox reports much better context for that particular class of error, just something that's useful to know)
About this statement:
Still has tons of stupid JS problems – implicit globals, type coercion everywhere (with JS primitives), slow as molasses.
There are plenty of globals, but they are intentional. If there are a few strays becoming global, they are bugs we'd be happy to fix. In user code, the global situation is actually slightly better than vanilla JS because we give any top level vars file level scope rather than global scope.
And finally:
About a 10% performance hit on tight loops if you use Obj-J message sending in them.
That sounds off to me. You can't blindly trust the WebKit or Firebug profilers, because they are not time based, but rather call based, which disproportionately affects short methods.
But even if its true, if a 5-10% performance hit on a critical loop is important, there's nothing stopping you from grabbing the method implementation and calling it directly, completely negating any potential performance hit.
One line of code will grab and store a method implementation, then you can just call it directly in your code:
var sel = @selector(aSelector:),
impl = class_getMethodImplementation([object class], sel);
for (var i=0; i<1000; i++)
impl(self, sel, arg1, etc);
In general, on the scale of an entire application, the overhead of message sends is much less than 10%.
Most of my errors are syntax errors, not programming errors, and indeed they are annoying in WebKit/Safari/Chrome. Firefox will sometimes give me the line, sometimes it won't. The named methods and profiling do indeed work well (I wouldn't lump profiling under debugging though.)
There are plenty of globals, but they are intentional. If there are a few strays becoming global, they are bugs we'd be happy to fix. In user code, the global situation is actually slightly better than vanilla JS because we give any top level vars file level scope rather than global scope.
Yeah, I'm talking about my code, not yours :)
But even if its true, if a 5-10% performance hit on a critical loop is important, there's nothing stopping you from grabbing the method implementation and calling it directly, completely negating any potential performance hit.
Right, that's what I do, just like in Obj-C/C.
And I'm definitely not going to argue about the performance of Cappuccino as a whole. I find it to be the best performing browser GUI framework.
edit: I use the profiler in Chromium, if that matters. :]
Some comments; I'm focusing on the negatives below, but I'll note that Cappuccino is a truly fantastic idea and exactly what web development should be.
Obj-J is more verbose than regular JavaScript. More use of objects and method selectors than callback functions. I usually prefer callbacks to delegate objects. It's easy to just make a catch-all object and use that with an anonymous function if you'd rather not specify a class for something that requires a delegate method, though it's not idiomatic Cappuccino/Cocoa.
I have to agree here -- delegates are a really poor replacement for closures, which is one thing JS can do pretty well. Delegates are definitely idiomatic Objective-C (although, Obj-C now has blocks), but it'd be nice if the standard libraries embraced closures.
Awful debugging. Worse than regular JS debugging. Usually can't even easily tell what line a syntax error is on.
I found this to be an enormous issue, especially due to the fact that without a compiler, I tended to have stupid type errors cropping up that took way too long to debug.
Mostly non-existent documentation. Still in rapid development, things change a lot. If you don't already know how to use Cocoa, expect to be totally lost.
The lack of stable releases, a clean binary installation (don't clutter up my system), proper documentation, et al, makes the project fairly difficult to approach -- especially without a type-checking compiler and poor debugging support. It's a bit of a moving target if you're going to try and use it, and there's a lot of gotchas that will require you to go to the source to figure them out.
Not sure what you mean by lack of stable releases. Are you saying that the releases are not stable, or that the release schedule is not stable?
I believe our releases have been fairly solid, but I do admit they don't follow any predictable schedule. We'd like that to change, but there are higher priority problems for us at the moment.
We also do offer a clean installer. First, all of cappuccino works without installing anything. It's self contained in a single app folder. Second, the tools all come bundled in one installer, which puts files wherever you like, defaulting to /usr/local/share/objj. We ship the documentation with the same download.
And as for the type-checking compiler part, we actually have an experimental type-checking runtime available on github. Improvements are, as always welcome. But not having a type-checking compiler is certainly par for the course in the JavaScript world, so I don't quite see how it counts against Cappuccino.
All that being said, yes it is young, yes it is a moving target, and yes there's a lot of work left to be done.
Not sure what you mean by lack of stable releases. Are you saying that the releases are not stable, or that the release schedule is not stable?
Both -- the releases were generally infrequent and tended to have issues that require running the latest versions from git to resolve.
We also do offer a clean installer. First, all of cappuccino works without installing anything. It's self contained in a single app folder. Second, the tools all come bundled in one installer, which puts files wherever you like, defaulting to /usr/local/share/objj. We ship the documentation with the same download.
My experiences trying to build from source (which was necessary as the releases fell considerably behind the development with requisite bug fixes) resulted in a bit of a mess in my home directory and the destination root (as well as interdependencies between), rather than just building cleanly in-place, but perhaps I was operating it incorrectly.
And as for the type-checking compiler part, we actually have an experimental type-checking runtime available on github. Improvements are, as always welcome. But not having a type-checking compiler is certainly par for the course in the JavaScript world, so I don't quite see how it counts against Cappuccino.
The primary count against Cappuccino vs straight JS is the difficulty in tracking down issues when they inevitably emerge. It sounds like things might have improved for Safari 4 users, however.
Not that I wouldn't mind type-checking for JS, too.
All that being said, yes it is young, yes it is a moving target, and yes there's a lot of work left to be done.
Absolutely. Please don't take my criticism as anything but friendly intent.
Note that you don't actually need to run the installer. You can just add "Tools/objj/bin" from the download or "$CAPP_BUILD/Release/env/bin" from the build to your PATH.
We probably don't make that clear anywhere, sorry.
Regarding delegation, I feel both closures and delegation have their place. We have been adding closure-based API in the areas we feel make sense (things that have a single expected callback return for example). However, I feel that things like TableView delegates and data sources still benefit much more from the delegate model than the closure model, and yes its because its more restrictive. If you look at NSTableView, it has many many datasource and delegate methods that are intricately related, and forcing you to group them in an object leads to better code in my opinion.
Perhaps more importantly, delegates and data sources allow you to do the Interface Builder-style visual development that we are aiming for. There really is no way to do this sort of thing with closures, unless you consider "double click on an object and type some code" to be visual development, which I do not. This is why I think closures make a lot of sense for things like network connections, callbacks for panels, etc. but less sense for things that in the common case really do represent connections and interactions between objects.
Interestingly though, we have recently been thinking of ways of "allowing both" easily. In other words, either making everything closure based behind the scenes and providing additional APIs for delegate, or making everything delegate based and transparently creating anonymous delegate objects for closures.
Yeah I find that delegation makes more sense in an OO context when the states between the delegate and other object are closely entwined. TableView data source is a perfect example, basically the two states need to stay consistent with each other but provide several standardized methods for modifying or reporting changes to state, which is where I think delegate methods shine. "Just waiting for something to return" is where I think they tend to be cumbersome when you have lambdas at your disposal.
In this regard I think JS and Obj-C are now starting to converge, which is interesting.
I saw this a long time ago and thought, "cool, but what about scalability, performance, etc..." But now there is back-end support. I'd like to see how this performs with the Lift framework. Cool project.
Great work! I'm really looking forward to using cappuccino for my next project, I think it will be a perfect fit.
In the blog post, you mentioned several backend solutions to work with cappucino. Which would you say is most mature, and which would you recommend? Using Objective-J on the backend would certainly be preferable, so that the developer can stay in one context the whole way.
Also, many solutions are going to end up having a model layer in the UI and a model layer on the server that will need to stay in sync. Are you guys working on any solution to automate this?
Objective-J on the backend is still in it's infancy, so I'd recommend it if you enjoy being on the bleeding edge.
We don't have any sort of Objective-J server-side framework, but you can use emerging JSGI-compatible JavaScript ones, like ActiveJS (Rails-like, http://activerecordjs.org/), NitroJS (http://www.nitrojs.org/), Bogart (Sinatra-like http://github.com/nrstott/bogart/tree/master) or just write raw JSGI application using Jack or custom middleware, which is actually perfectly adequate in many cases.
Yes I should also note that Objective-J and Cappuccino run well on the server-side (using the Narwhal standard library: http://narwhaljs.org), I only meant that there's no Objective-J server-side web application framework (which you don't need in many cases).
Essentially, we run the same code on the server side as we do on the client side in order to unarchive the objects that get archived on the client, and then operate on them. For example, when you hit "export", the presentation is archived, sent over the wire, unarchived (using the same exact model code), then converted to PPT or whatever.
You could also for example make an entire UI in code on the server, complete with connections to abstract objects, then send that entire object graph over the wire and show it on the client.
I've spent a small amount of time working through the Cappuccino docs and tutorials, but never used it to build a project because it feels like it is so different from the typical JS I'm used to writing. That's not a criticism, just a description of the major hurdle I've encountered working with Cappuccino.
Instead of having a smattering of tutorials and example apps, what would be really help would be a set of real world problems and solutions to those problems using Cappuccino (a list of N perhaps?). It would be especially compelling if it could be shown that those problems are more elegantly or simply solved by the use of Cappuccino.
I'm not sure if this is more along the lines of what you mean, but this tutorial got written recently which explains specific problems/solutions in building an entire app: http://blog.springenwerk.com/search/label/Cappuccino .
Perhaps an explicit list of when you would and wouldn't want to use Cappuccino is a good idea though
First time I see that - is there any particular reason why would one use that for applications instead of, for example, GWT?
edit: I am watching screencasts now from http://cappuccinocasts.com (I'm not Ruby guy though - PHP, but doesn't matter) - and I am wondering how the hell are you
1) how to debug/profile this? What, a hunch or traces and alerts?
2) .j files are in plain sight to anyone, not obfuscated
3) Why .j at all in production, why not compile down to javascript?
4) It seems nice from a perspective of a desktop guys viewpoint (here is one!)
1) As mentioned in the blog post, we have taken the time to actually build in ObjJ support into WebKit's debugger and profiler. I would classify this as one of the best debugging and profiling experiences for JS out there (not that there is much competition). More info here: http://www.alertdebugging.com/2009/04/29/building-a-better-j...
2/3) There is no need to ship .j's in production. We ship a compiler/obfuscator/compressor that will spit out the same illegible code that you would get if you were just using JavaScript with a compressor. It will also concat all the files together to dramatically improve load times.
This sounds like it might be true until you write a large application and then type safety suddenly makes a lot of sense, even a stupid non-inferred type system like Java's.
Have you actually tried to write anything with GWT and/or used Java and it's wonderful tools? And how does it make more sense to basically have a pseudo-VM running on top of JS than to spurt out heavily optimized JS code like GWT does? I'm really interested in answers to both questions.
I work in gwt everyday and there are lots of pluses to it such as the easy communication between the client and server and taking away a lot of the dom headaches. However, I have several issues with it. Compile time from java to javascript is very slow, simple app takes a few minutes to compile. You typically will work in a hosted mode browser so changes are on the fly, in many scenarios things work in the hosted mode browser, but fail inside a normal browser, regex and bigdecimal use are two such pain points.
A big issue that I have with it is that developers end up putting way too much business logic inside the gwt portion of an app, simply because its just java anyway, right? You can't really blame gwt for bad programming, however, because of the notion of its just java it easily allows developers to not think and just put business logic in the ui. If this was javascript developers would much rather do the more complicated business-y things on the server side (typically where it should belong), rather than in javascript because most people really dislike working in JS. I personally feel that its very difficult to build a gwt app while maintaining a clean well refactored codebase and doing TDD is also very difficult with the framework. I say difficult and not impossible, because I have done it in the past, but its not easy and really takes time and care. Again because its not easy to do these things developers tend to not do them, thus leading to messy, hard to change apps.
>simple app takes a few minutes to compile
>You typically will work in a hosted mode browser
I thought those issues are now thing of the past. At least that's what I saw in google i/o presentations.
For the other part it seems more like an issue with development approach and not GWT per se. I have only dabbled a bit with it and like it more than writing JS for full blown web apps.
Cappuccino intrigued me because of my background in desktop apps - albeit not Cocoa. There are many idioms I am used to, so I'll give it a spin.
I'm considering using cappuccino for a startup idea I have, but the lack of people using it and info out there on it makes me a bit gun shy. It makes me think I'll spend more time hacking away with capp rather than focusing on delivering a product quickly to see if people like it. For anyone else out there considering using it do check out http://cappuccinocasts.com
I've been watching the Capp project with great interest since its debut, and hoping against hope that it turns into a serious alternative to the mess that's out there today for web dev.
Now I'm worried that the combination of the Atlas delay and lack of serious Capp-based public websites is going to hurt its initial momentum.
That's missplaced idealism. You should very much use the soapboxes you created to tell people about news. This is "industry" news for people who are interested in capp. I go to capp.org regularly and see no changes and assume that progress has stalled.
I developed a few toy projects to learn each framework.
Cappuccino is an incredible technical accomplishment. I've done iPhone development, and it's true that you can easily map your Cocoa experience onto Cappuccino. However, when I hit a corner case such as embedding a SWF, the abstraction leak was a nightmare.
Sproutcore feels safer because it doesn't hide the fact you're working with HTML/CSS; you need to write it to create custom views. Inserting a SWF was straightforward.
The other reason I favor Sproutcore is the feeling Cappuccino has cargo cult issues. For example, Sproutcore uses namespaces while Cappuccino just prefixes initials. In Sproutcore you have "SC.Object" while Cappuccino uses "CPObject."
Cappuccino is still pre 1.0, so all of this could change, but if I had to choose a framework to write an app today, I'd go with Sproutcore.
I'm not sure what "cargo cult issues" are, but Cappuccino uses prefixed globals because they are strictly faster than using "namespaces" (which really aren't namespaces).
unless things have changed recently, SC's 1.0 beta is anything but stable. It's great for hobby projects, but I would worry if attempting to use it for production. I guess if you're starting a new project now, SC isn't a bad route. Will probably be stable soon.