New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open letter to gruntjs #669

Closed
twolfson opened this Issue Feb 16, 2013 · 5 comments

Comments

Projects
None yet
4 participants
@twolfson

twolfson commented Feb 16, 2013

https://twolfson.com/2013-02-15-open-letter-to-gruntjs

Dear gruntjs,

The following letter is about my thoughts and complaints of the recent upgrade from 0.3 to 0.4. Normally, I am enthusiastic about progression in the development world but this causes me much anger and frustration.

Introductions

My name is Todd Wolfson, I am open source enthusiast who is a huge fan of grunt in its current 0.3 form.

I have a lot of respect for the work you have done on grunt and the collaboration it has caused for among the JavaScript community.

However, I feel that the proposed changes are a step in the wrong direction; undoing tons of man-hours not just in grunt plugins, but in every project that relies on grunt (at least 5k if stargazers holds true).

Complaints

Changing interface without backwards compatibility

This honestly shocked me when I first heard about this. In fact, it shocked me so much that I was in denial until the date of writing this.

Since this is a minor update (as determined via semver), everything that worked before should continue to work. Clearly, since you are asking people to update their plugins, this is not the case.

Loss of elegance

This is the biggest pain point for me. It is why jQuery won and Dojo, YUI, MooTools, Prototype, and any others did not.

Task configuration

The new configuration interface is not as elegant nor as developer friendly as the previous one. For example,

var nonGruntConfig = {
  from: 'hello.js',
  to: 'world.js'
};

// grunt 0.3
var config = {
  src: nonGruntConfig.from,
  dest: nonGruntConfig.to
};

// The src was
config.src;

// grunt 0.4
var config = {};
config[nonGruntConfig.from] = nonGruntConfig.to;

// The src was
var srcs = Object.getOwnPropertyNames(config);
srcs[0];

I understand that the new interface makes adding batch files a lot easier. However, it is much more common to declare separate tasks for different file sets than share common options (e.g. jade:pages jade:views).

On the same note, the jshint plugin solved that problem much more gracefully in terms of interface.

Task registration

Tasks are registered as no longer single line strings. This was what made me fall in love with grunt. I hate the code bloat caused by ', ' and that rocked my world.

It is okay if the framework does the heavy lifting; that is what frameworks are meant to do.

Removing baked-in goodness

jquip, YUI, and ExtJS have gotten some traction but never any huge growth since they don't have batteries included.

However, grunt should be a framework for everything and more.

Batteries included

Your decision to abandon common tasks is a foolish one.

node comes with modules baked-in (e.g. http, fs) because it reduces the barrier to entry for everyone and lets you hit the ground running.

Easy extensibility

Programming in extensibility into applications is a great way to help out other developers that want to tweak modules for one-offs without forking.

The helper API was wonderful for this; virtually no barrier to entry and rich reusability once parts were registered.

The decision to remove this is short-sighted and causes a lot more pain/frustration for developers. It doubles the amount of maintenance and once again is at the cost of the developer and not the framework.

Finishing thoughts

You are not make.

You are not rake.

You are not cake.

You are better than this. Be proud of who you are. You don't need to change. You don't need to conform.

 

Sincerely,

Todd Wolfson

@ctalkington

This comment has been minimized.

Show comment
Hide comment
@ctalkington

ctalkington Feb 16, 2013

Member

I can't agree with most your comments. The changes fit better in the nodejs world and create shareable modules (helpers were grunt specific) and tasks in v0.5. well worth the changes.

once v0.4.0 is official, using contrib modules will be common place and let you easily roll your own setup with little work.

semver actually states the API is stable only after v1.0.0 at which point API changes require minor bump.

Member

ctalkington commented Feb 16, 2013

I can't agree with most your comments. The changes fit better in the nodejs world and create shareable modules (helpers were grunt specific) and tasks in v0.5. well worth the changes.

once v0.4.0 is official, using contrib modules will be common place and let you easily roll your own setup with little work.

semver actually states the API is stable only after v1.0.0 at which point API changes require minor bump.

@tkellen

This comment has been minimized.

Show comment
Hide comment
@tkellen

tkellen Feb 16, 2013

Member

Dear Todd,

We really and truly appreciate you taking the time to share your thoughts with us about this transition. It means a lot to know that you feel passionately about Grunt!

I'd like to respond to your concerns, so, here we go:

Loss of backwards compatibility
Grunt is in the first stages of development, and we are exploring a rather large problem space with this project. Things are not totally stable yet, but we are adhering to semantic versioning as best we can. Just in case you're not familiar with it, you can read the spec here. That said, here are rules 4 and 5:

  • Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
  • Version 1.0.0 defines the public API. The way in which the version number is incremented after this release is dependent on this public API and how it changes.*

Loss of elegance
Perhaps our documentation is lacking? You can accomplish what you're trying to do very easily in 0.4 using config.set and config.get. Please see this page in our API docs. Caveat: one of our final checklist items is going through the API docs before Monday to ensure they are accurate. If you run into issues with this, please let us know.

Task Registration
I'm not sure I follow what you mean here? Task registration is the same. Could you provide an example of this?

Batteries Not Included
The maintenance overhead and barrier to collaboration that comes with having all kinds of things bundled with Grunt is too high. For example, when a small feature is added to a task, releasing an entire new version of the task runner itself doesn't make any sense.

Since breaking our plugins into individual repos we've seen a huge surge in PRs. So far the response to this change has been overwhelmingly positive. That said, your concern is valid, and the primary way we plan to deal with it is by improving our documentation (we have a new website to go with this launch).

We may also deal with this by using gruntcollections, which allow multiple plugins to be packaged and loaded together. You can see how that works here.

Easy extensibility
registerHelpers was deprecated because it is a messy global namespace that is prone to clobbering when you start loading plugins from various sources. Also, the grunt object will not be passed around in the future, rendering registerHelpers useless.

If you have two files which you are trying to share code with, you should use node require. It was built for exactly this purpose. We've maintained the old baked-in helpers, if you like to use them or see how to implement a helper of your own, please see this repo.

Final thoughts
We are hugely proud of Grunt, especially Grunt 0.4! These changes were not made in an effort to conform with anything but our vision of what Grunt should be. I sincerely hope this response will help you to be as excited about Grunt 0.4 as we are. A lot of thought and countless hours of effort have gone into making this release. If you can't stand these changes, please continue to use Grunt 0.3 for as long as you wish!

Member

tkellen commented Feb 16, 2013

Dear Todd,

We really and truly appreciate you taking the time to share your thoughts with us about this transition. It means a lot to know that you feel passionately about Grunt!

I'd like to respond to your concerns, so, here we go:

Loss of backwards compatibility
Grunt is in the first stages of development, and we are exploring a rather large problem space with this project. Things are not totally stable yet, but we are adhering to semantic versioning as best we can. Just in case you're not familiar with it, you can read the spec here. That said, here are rules 4 and 5:

  • Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
  • Version 1.0.0 defines the public API. The way in which the version number is incremented after this release is dependent on this public API and how it changes.*

Loss of elegance
Perhaps our documentation is lacking? You can accomplish what you're trying to do very easily in 0.4 using config.set and config.get. Please see this page in our API docs. Caveat: one of our final checklist items is going through the API docs before Monday to ensure they are accurate. If you run into issues with this, please let us know.

Task Registration
I'm not sure I follow what you mean here? Task registration is the same. Could you provide an example of this?

Batteries Not Included
The maintenance overhead and barrier to collaboration that comes with having all kinds of things bundled with Grunt is too high. For example, when a small feature is added to a task, releasing an entire new version of the task runner itself doesn't make any sense.

Since breaking our plugins into individual repos we've seen a huge surge in PRs. So far the response to this change has been overwhelmingly positive. That said, your concern is valid, and the primary way we plan to deal with it is by improving our documentation (we have a new website to go with this launch).

We may also deal with this by using gruntcollections, which allow multiple plugins to be packaged and loaded together. You can see how that works here.

Easy extensibility
registerHelpers was deprecated because it is a messy global namespace that is prone to clobbering when you start loading plugins from various sources. Also, the grunt object will not be passed around in the future, rendering registerHelpers useless.

If you have two files which you are trying to share code with, you should use node require. It was built for exactly this purpose. We've maintained the old baked-in helpers, if you like to use them or see how to implement a helper of your own, please see this repo.

Final thoughts
We are hugely proud of Grunt, especially Grunt 0.4! These changes were not made in an effort to conform with anything but our vision of what Grunt should be. I sincerely hope this response will help you to be as excited about Grunt 0.4 as we are. A lot of thought and countless hours of effort have gone into making this release. If you can't stand these changes, please continue to use Grunt 0.3 for as long as you wish!

@twolfson

This comment has been minimized.

Show comment
Hide comment
@twolfson

twolfson Feb 16, 2013

@tkellen Thank you for the detailed response. I appreciate you taking the time to address my concerns.

Additionally, I apologize that I am about to drag this on.

Loss of backwards compatibility

You are totally right here. I have always thought of minor changes as changing the smallest subset without common usability. This usually means deprecation over a few minors.

Loss of elegance

I was referring to the majority of grunt-contrib plugins moving to a

{
  files: {
    'hello.js': 'world.js'
  },
  options: {}
}

format over

{
  src: 'world.js',
  dest: 'hello.js'
}

However, it seems my concerns were false since the this.file API still exists.

Task Registration
Sorry for being unclear on this. I was referring to aliasing not actual registration. As noted in the creating tasks and migration pages,

// No longer supported
grunt.registerTask('default', 'build test');
grunt.registerTask('test', 'qunit');
grunt.registerTask('build', 'lint replace concat min');

// New syntax
grunt.registerTask('default', ['build', 'test']);
grunt.registerTask('test', ['qunit']);
grunt.registerTask('build', ['lint', 'replace', 'concat', 'min']);

This is a mechanical change at the loss of elegance. I am not sure if you have taken any design courses but it is the little things that can make a huge impact.

Case and point: jQuery.on method has the functionality as jQuery.bind and jQuery.delegate. However, that small change makes the API more intuitive and easier on the developer.

// DOM level 0 interaction
div.onclick = function () { console.log("Hello world!"); };

// jQuery
div.on('click', function () { console.log("Hello world"); });

Batteries not included
I totally understand where you are coming from on this. However, once again to use jQuery as an example, they don't release a new version on every change. They bundle the updates into version changes.

It is great that you are breaking up tasks into modules but that doesn't mean grunt-contrib can't come pre-packaged with grunt (or at least the original set of grunt tasks).

Easy extensibility
Could you elaborate more on there not being a common grunt object? Are you moving away from the inversion of control design pattern?

you should use node require

Please don't tell people how to write code. I have a lot of faith in open source developers that they can make the decision to break up their code at the proper places. Some know this, some have to learn it.

I am saying give them more options so that they can make their code extensible even if it is unintentional.

Final thoughts
I totally understand where you are coming from and respect that you want to make improvements. I just feel that these actions are counter-productive and reduce the velocity of grunt and grunt using community.

twolfson commented Feb 16, 2013

@tkellen Thank you for the detailed response. I appreciate you taking the time to address my concerns.

Additionally, I apologize that I am about to drag this on.

Loss of backwards compatibility

You are totally right here. I have always thought of minor changes as changing the smallest subset without common usability. This usually means deprecation over a few minors.

Loss of elegance

I was referring to the majority of grunt-contrib plugins moving to a

{
  files: {
    'hello.js': 'world.js'
  },
  options: {}
}

format over

{
  src: 'world.js',
  dest: 'hello.js'
}

However, it seems my concerns were false since the this.file API still exists.

Task Registration
Sorry for being unclear on this. I was referring to aliasing not actual registration. As noted in the creating tasks and migration pages,

// No longer supported
grunt.registerTask('default', 'build test');
grunt.registerTask('test', 'qunit');
grunt.registerTask('build', 'lint replace concat min');

// New syntax
grunt.registerTask('default', ['build', 'test']);
grunt.registerTask('test', ['qunit']);
grunt.registerTask('build', ['lint', 'replace', 'concat', 'min']);

This is a mechanical change at the loss of elegance. I am not sure if you have taken any design courses but it is the little things that can make a huge impact.

Case and point: jQuery.on method has the functionality as jQuery.bind and jQuery.delegate. However, that small change makes the API more intuitive and easier on the developer.

// DOM level 0 interaction
div.onclick = function () { console.log("Hello world!"); };

// jQuery
div.on('click', function () { console.log("Hello world"); });

Batteries not included
I totally understand where you are coming from on this. However, once again to use jQuery as an example, they don't release a new version on every change. They bundle the updates into version changes.

It is great that you are breaking up tasks into modules but that doesn't mean grunt-contrib can't come pre-packaged with grunt (or at least the original set of grunt tasks).

Easy extensibility
Could you elaborate more on there not being a common grunt object? Are you moving away from the inversion of control design pattern?

you should use node require

Please don't tell people how to write code. I have a lot of faith in open source developers that they can make the decision to break up their code at the proper places. Some know this, some have to learn it.

I am saying give them more options so that they can make their code extensible even if it is unintentional.

Final thoughts
I totally understand where you are coming from and respect that you want to make improvements. I just feel that these actions are counter-productive and reduce the velocity of grunt and grunt using community.

@cowboy

This comment has been minimized.

Show comment
Hide comment
@cowboy

cowboy Feb 17, 2013

Member

Todd, thanks for your feedback.

Just so you know, most of the issues you mention have already be discussed in the issues tracker. For example:

  • gruntjs/grunt#305 - Deprecate task.run("task1 task2") syntax to allow task names/args to contain spaces
  • gruntjs/grunt#396 - config.get, <%= %> template processing, no string values, removing helpers and directives, etc

I know there are many more, because there have been a lot of changes, and we've discussed all of them in one form or another. That's partially why it's taken nearly a year to go from 0.3 -> 0.4.

If you're really interested in being involved in discussion about Grunt, it would be most helpful for you to get involved in those discussions as they happen. That way, we can integrate your feedback before we've commited to anything.

All that said, we've had overwhelmingly positive feedback about Grunt 0.4 during the release candidate phase, so I'm not too worried about Grunt 0.4's acceptance. And don't worry, we can always fix major issues in 0.5 if necessary.

I'm going to close this issue to try to demotivate @tkellen from responding further, as I know he has a lot of work to do. After all, we're releasing Grunt 0.4 in just a few days!

Member

cowboy commented Feb 17, 2013

Todd, thanks for your feedback.

Just so you know, most of the issues you mention have already be discussed in the issues tracker. For example:

  • gruntjs/grunt#305 - Deprecate task.run("task1 task2") syntax to allow task names/args to contain spaces
  • gruntjs/grunt#396 - config.get, <%= %> template processing, no string values, removing helpers and directives, etc

I know there are many more, because there have been a lot of changes, and we've discussed all of them in one form or another. That's partially why it's taken nearly a year to go from 0.3 -> 0.4.

If you're really interested in being involved in discussion about Grunt, it would be most helpful for you to get involved in those discussions as they happen. That way, we can integrate your feedback before we've commited to anything.

All that said, we've had overwhelmingly positive feedback about Grunt 0.4 during the release candidate phase, so I'm not too worried about Grunt 0.4's acceptance. And don't worry, we can always fix major issues in 0.5 if necessary.

I'm going to close this issue to try to demotivate @tkellen from responding further, as I know he has a lot of work to do. After all, we're releasing Grunt 0.4 in just a few days!

@cowboy cowboy closed this Feb 17, 2013

@twolfson

This comment has been minimized.

Show comment
Hide comment
@twolfson

twolfson Feb 18, 2013

@cowboy Thanks for the consideration and I apologize for causing more noise than necessary.

Unfortunately, if I watched every repo that I cared strongly about, I would have no more free time for new projects.

Thank you once again for addressing my concerns.

twolfson commented Feb 18, 2013

@cowboy Thanks for the consideration and I apologize for causing more noise than necessary.

Unfortunately, if I watched every repo that I cared strongly about, I would have no more free time for new projects.

Thank you once again for addressing my concerns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment