21 March 2016

DeprecationAssistant: Aiding Developers With Simple Deprecations

Last week I've created DeprecationAssistant: a little plugin that can help you with deprecations. This is a short story behind it and around it.

The Context

Software is evolving constantly and it is a common process when a method becomes deprecated in favor of another (or a combination of them). Now it is a good practice to send a deprecation message deprecated: or deprecated:on:in: so self (so everyone invoking this method will be warned) and after that use the contemporary implementation (if possible) so if the execution is resumed, the method will return the expected result. Here is an example of a deprecated method:
Color>>#asHTMLColor
   self
      deprecated: 'use #asHexString and prepend #'
      on: ' 1 September 2015'
      in: 'Pharo5'.

      ^ '#', self asHexString
Now if you have a method that does: Color red asHTMLColor you will get a warning saying "use #asHexString and prepend #". But the needed implementation is already available in asHTMLColor, so why cannot we just copy it into our code? Well, now we can :)

The Assistant

This project is called similarly to QualityAssistant, my most significant contribution to Pharo. But unlike it's big brother DeprecationAssistant is rather small project that was developed only in one day (not counting the time I've spent for battling RefactoringBrowser components). They still share the main concept: to assist a developer with the tasks that can be performed by a machine. Now when a deprecation warning occurs you are provided with an option to resolve it automatically by inlining the contents of deprecated. You will be presented a diff of the proposed changes before applying it.


You can install DeprecationAssistant from the Pharo Catalog or by running:
Metacello new
   repository: 'github://Uko/DeprecationAssistant';
   baseline: 'DeprecationAssistant';
   load

Related Work

This is not the first time someone tries to provide assistance in the deprecation context.

Camille Teruel once made Deprecator. An amazing project that allows developers to specify a transformation rule that can be used to fix the deprecation. Shortcomings: as far a I know most of developers have no clue how to write transformation rules (because of the certain reasons). In my case I rely on a plain Pharo code that everyone know how to write and should write if he/she wants to allow resuming an execution of the deprecated method. My approach is not an alternative but rather an extension that requires less job from the developers.

Marcus Denker made an experiment of automatic rewriting of deprecated methods the are being executed. His approach also relied on the rewrite rules, but the idea of automated transformation during execution can be also applied here.

Lesson Learned

For the rewriting functionality I was using inline method refactoring from the Refactoring Browser project. The functionality is very rich as it provides the 'self' resolutions, handles temp naming conflicts and much more… On the other hand the api is super high-level and oriented on the specific task. To make it work you have to pass a method, and a selection in the method, and it will look up the message node to replace and the source class of the method to inline. Now I have both the node and the source class, and it was very complicated to make it work the way I wanted. In the end I've simply copied the inline refactoring class and changed it to work the way I need. Refactoring Browser project is probably 20 years old and I noticed that many of these old Smalltalk projects have a very rich functionality hidden behind an ugly API. Nowadays objects are more independent probably because we have more tools that allow each object to have it's own representations, actions, etc…

I don't know how it worked before, but now Pharo methods return a Refactoring Browser model when asked for AST. This provides many benefits, but we also have to be careful. RB nodes have a possibility to contain changes and RB tools tend to change the state of the model that they are working with. So if you pass an existing AST into some RB tool you risk ending up with a broken AST.



Give DeprecationAssistant a try, give me a feedback. It's all about making developers life easier by making tools more meaningful.

No comments:

Post a Comment