Thursday, November 15, 2012

Project Report - Less4j


Few months ago I decided to create java port of less.js. Less is an extension of CSS - it adds constants, mixins, ruleset nesting, namespaces and so on. Both reasons why I picked up less and short less introduction are written in introduction into less.

This report starts with current project status and its possible future directions. Second part recaps development and my experiences with used tools. Finally, the last part sums up why did I started with the project in the first place and whether it was worth it.

Current Status

Less4j can be used as both library and command line compiler. The library version is available in Maven central and command line compiler can be downloaded from Github downloads page.

The project is hosted on Github. Github provides also a simple issue tracking system and extremely simple wiki for documentation. Less4j uses also hosted continuous integration named Travis.

The biggest language features are already there, at least in some simple version:
  • variables,
  • operations,
  • nesting,
  • mixins,
  • namespaces.

Just as less.js, less4j keeps comments on place. Translation will not remove them.

Remaining features should be doable without major rewrite. There are only two exceptions:
  • Escaping which allows to insert any non-parseable input into less.
  • Browser hacks which allows to write browser specific css. They take advantage of various browsers bugs and theoretically should not be used. Practically, they are often useful and sometimes unavoidable.
Both will shake things a bit for sure, but since I have not thought about them too much yet, it is hard to make any guesses on how much.

I try to have the documentation for all features completed at the release time. It captures what I intended to implement and how less language works. The idea is to have all potentially confusing points written out and to give warning on things that may change in the future.

Future

Less.js have big plans for future. First, they plan to introduce backward incompatible changes in the 1.4.0 version. They also plan to introduce language configuration options: you will be able to turn certain syntaxes on and off.

Backward Incompatible Changes
They have very solid reasons for all planned backward incompatible changes. New syntax will be a bit more strict because current looser rules occasionally cause problems. Changes will remove some "tricky and subtle" situations from the language.

I was tempted to chase directly the future 1.4.0 version. In addition to previously stated arguments, it would be better if new language users would use new syntax and it is hard to guess how long will less.js support the old style.

On the other hand, it is not entirely sure how it will look when it will be done. The discussions are still going on:

Optional Syntaxes
Optional syntaxes are quite interesting challenge, but I still have to see whether they make sense for the compiler port. They are not priority for now. It is more important to get at least one version of the language done.

Experiences

This chapter contains my experiences and opinions on tools used in the project.

Porting Language
Writing core was much faster and easier then I expected. Two things greatly helped to start the development:
  • Less.js has unit tests I could take and use.
  • A basic CSS 2.1 grammar is available on antlr site.

Granted, the grammar taken from antlr site has some bugs, so reserve few days for testing and debugging if you plan to use it. It also contains only CSS 2.1, version 3 features have to added. However, those are only minor problems. Especially considering that w3c published also tests for major parts of css specification.

Less language turned out to be much more elusive then I expected. Every major language feature has a lot of undocumented sub-features. Every time I think that the feature is finished, I end up finding that less.js can actually do much more. Although it feels like all majors features are already there, I'm sure that it is just because I do not know them all.

Less documentation is sparse and the only way to learn about features is to read discussions in their issue database. Of course that has some benefits too: their issue database is a great resource of potential tests and edge use cases. Plus, the ability to read past discussions on features helps me understand and appreciate less.js design decisions.

Learning Compilers
I tried to watch coursera compilers lectures in the beginning, but they did not seemed to help me.

"Pragmatic language implementation patterns" book turned out to be more interesting and useful. It is well written and has a short chapter on language to language translation. I guess that "Compilers - Principles, Techniques, and Tools" could also contain something useful, but I did not read it.

I happen to use design not recommend by the pragmatic book and I do understand why they do not recommend it by now. Less4j creates abstract syntax tree for less and then transforms it into abstract syntax tree for css. The book does not explain why it is not ideal, so here it goes: it is more error prone then building ad hoc structures they recommend and it occasionally requires more work. However, I still think that less4j is small enough and less is close enough to css to make these disadvantages small.

Antlr
I puzzled over antlr few times, but its help was big anyway. I guess I would still be in the css parsing phase without it.

Most troubles have been caused by the fact that css is very loose language and by my use of semantic predicates (java conditions embedded into grammar). First, specifying grammar for strict language would be easier almost by definition. Second, semantic predicates tend to confuse antlr generation phase. Antlr then sees multiple ways to parse the same input and tend to suppress wrong alternatives on such inputs.

Of course, I could imagine also better antlr-maven-eclipse integration, the one that would not occasionally hide errors and warnings from me. Of course, I also could fix that one by myself if it would really bothered me.

I would also welcome callbacks on rules entering and leaving. It would be great if I could have a method to be called each time the parser leaves some rule. I do know about the after keyword, but that one has to be copied after each rule separately and is ignored in case of parse error.

Maven Release
Releasing the library into Maven central for the first time takes some time, but any subsequent release is a question of two commands. The release plugin creates a tag, increases version in pom.xml, commits changes into repository, builds the library, gpg signs it and uploads it into maven central. All that remains is to sign into Sonatype nexus and click two buttons to actually release it. Simple and fast.

First release is a bit longer. First, you have to configure pom.xml for release and make sure that you project follows Sonatype guidelines. Then there is some bureaucracy: create and publish gpg key, create an account and open issue in Sonatype tracker. All new projects are checked by a human and if your project does not follow guidelines, you will have to change it.

All along with examples is described in this blog post. I would just add that gpg signing plugin has a bug and is unable to ask for gpg passphrase. You have to add the switch -Dgpg.passphrase=<passphrase> to the mvn release:perform command to make it run.

Github
Github was made for coding and it shows. It has great code collaboration tools. It can show colored diff for any commit and anyone can comment on any code line. It provides all kind of stats about commit frequencies and sizes. Do not forget the integrated hosted continuous integration (provided by different company), it is also very useful. And so on, the more people collaborate on commits, the better Github is.

I would welcome also a bit more elaborate issue tracking system, more powerful wiki and more customizable notification system. Issue can be opened and closed, can have labels and that is it. It would be useful to have more bug statuses, special field for priority/severity, division on bugs and features and so on. I would use them if I would have the choice. While it is possible to use labels for that purpose, I would prefer not having to do it.

Wiki is clearly not meant for big documentation. Syntax wise, it supports 10 different syntaxes, the default one being markdown. On the other hand, it is impossible to generate table of contents. It does not support refactorable page linking. Ok, I'm not sure whether there is a system with such support. But, those other systems can automatically look for all broken cross links. While it is understandable that Github does not allow javascript, I still miss it.

Projects search on Github is also very simple, but I do not care about that when writing a project.

Conclusion

This chapter contains overall accounting: was it worth the time and effort? The first part explains why I started less4j in the first place and what I was expecting out of that. The rest sums up benefits and cons of the project.

Motivation
Bringing less.js into java is easy even without this port. There are already tools that use Rhino to comfortably integrate it into Java projects. Strictly speaking, porting the thing was not necessary. It is usable as it is.

On the other hand, writing the compiler would allow me to learn more about the language I was starting to like. It would also allow me to learn more about ANTLR and to use in a real world non-trivial project. I also liked the idea of coding a project potentially useful to other people too.

On the less egoistic side, I also through that using native java implementation could have some advantages - some people prefer to use "native" tools. It could have more comfortable API, error reporting and the parser could be used for other purposes later on. For example, I could use it to write a Less Eclipse plugin.

Lastly, I would be in a great position to document tricky aspects of the language. After all, I would encounter most of them during the development.

Personal Pros/Cons
Most important project disadvantages:
  • It took my attention away from this blog, especially:
    • I did not wrote Eclipse plugins part 2 yet.
  • The project is highly addictive.

Most important project benefits:
  • The project is highly addictive.
  • Everything else, especially:
    • It is highly enjoyable coding.
    • Tried ANTLR on something real.
    • Learned a lot about less.

Final Conclusion
Definitely worth it.

1 comments:

Alex said...

Great work, Mária!
Thank you for your contribution, it is definitely useful for many people. I think that releasing a 1.0.0 version would increase people confidence in using less4j. I appreciate your dedication and my only regret is that I didn't find enough time to contribute and learn ANTLR (missed a great chance :)..

Though the less compiler can be ported to java using rhino, nodejs or nashorn (in java8), it is still useful to have a native cross platform compiler. Hopefully this will be adopted by many developers in the future and will become a mainstream someday :)...

Keep doing great work!

Post a Comment