A look at the architecture changes in Feathers 3.0.0

Over three years ago, I released Feathers 1.0, targeting Starling 1.3. Today, I release Feathers 3.0 targeting Starling 2. It’s been an amazing experience to work hard and improve an open source project every day with the enthusiastic support of both Adobe and the wonderful Starling community.

As a new major release, Feathers 3.0 gave me the opportunity to re-imagine part of the Feathers architecture, based on feedback from developers who use Feathers in their apps and from my own experiences building new components. Let me point out a few of those architecture changes and the reasons why I made them.

Shared Constants

Way back in 1.0, I should have moved shared constants into their own classes. Instead, with each new version of Feathers, duplicate constants like HORIZONTAL_ALIGN_LEFT, SCROLL_POLICY_ON, and others repeatedly appeared throughout the Feathers codebase. I now realize that a single place to find HorizontalAlign.LEFT and ScrollPolicy.ON would have been better, and this is one of the things I cleaned up in Feathers 3.0.

When I started developing these components, I defined constants on the classes that used them because it seemed very convenient. If you needed to use a constant with the Slider class, you’d find it… on the Slider class! At the time, Feathers didn’t use many subclasses, and it had only a handful of components and layouts. I didn’t fully realize that defining constants like this wouldn’t scale very well as Feathers grew much larger over time.

By the time I started developing Feathers 2.0, I got frustrated as I saw myself duplicating constants in subclasses (so that developers wouldn’t need to know the inheritance hierarchy to find them), and I sometimes forgot to do it when new constants were added to the base classes. It was clear that things were getting a little messy in ways that I did not foresee. However, I worried that making this change would be too disruptive at the time, with the big theme changes that were included in Feathers 2.0, so the constants stayed as-is.

As I started working on Feathers 3.0 this year, I decided that this change finally needed to happen. It would indeed be disruptive, but the duplication and its side effects were getting out of hand. Using shared constant classes like VerticalAlign, RelativePosition, and Direction would be way easier for me to maintain going forward with a smaller learning curve and fewer bugs. I really wish I had made this change three years ago, but if I had waited for everything to be perfect, 1.0 would never have been released.

I’ve done my best to ease the pain of this migration. The old constants still exist, and they will not be removed until at least 18 months from now or until the next major version (whichever takes longer). Take your time switching over, and don’t feel like it must happen immediately when you upgrade. Be sure to try out the regular expressions in the Feathers 3.0 Migration Guide. You can use them with your editor’s Find/Replace feature to quickly swap out the old constants with the new. I used them on the example themes, and it was so much faster than doing the replacements manually.

saveMeasurements()

When a Feathers component’s width or height is not set explicitly, it needs to calculate appropriate dimensions during validation. Usually, this calculation is based on the dimensions of its skins and sub-components. Custom component developers will be familiar with the old setSizeInternal() method that was used to commit the calculated dimensions. This method has been deprecated and replaced with one named saveMeasurements() that accepts width and height the same as before, but also minimum dimensions as well.

Previously, the minWidth and minHeight properties defaulted to 0, and you could change them manually. However, in many layouts, the minimum dimensions may be used as a fallback. For instance, in a VerticalLayout where percentWidth is specified on children, their minWidth values of those children may be used as a fallback when the parent container’s width is not set. In previous versions, 0 would be used, which wasn’t always ideal.

Now, all core Feathers components calculate their minWidth and minHeight when needed. Custom component developers are encouraged to do the same.

As a bonus, this change helped me discover me some places where I could optimize Feathers by avoiding validation when it wasn’t necessary. This leaves Feathers in a better place for new, more advanced components that may be coming in future versions.

feathers-compat

As Feathers evolves, some APIs are inevitably deprecated and, eventually, removed. For instance, Feathers 3.0 includes a new class named ImageSkin that replaces an “advanced” class named SmartDisplayObjectValueSelector that was more cumbersome to use. Both optimize skinning by reusing the same display object with multiple textures, but ImageSKin does it in a better way.

It would be better if developers did not use SmartDisplayObjectValueSelector anymore, and I’d like to remove it from Feathers. However, existing code doesn’t rewrite itself, so developers may want to continue using this class for a while and still benefit from the bug fixes in Feathers 3.0. That’s where feathers-compat comes into play. Classes like SmartDisplayObjectValueSelector can be moved into feathers-compat so that they’re still available, if needed.

If you’re upgrading an app built with an earlier version of Feathers, and you find that some classes are missing, be sure to check if they’re included in feathers-compat.

New components on the way!

Feathers now has a stronger foundation that has been re-enforced with these architecture improvements (not just in Feathers, but in Starling too!). Starting with version 3.1 and beyond, I can start adding new and more advanced components. Stay tuned for news on what I have planned!

Also, thank you again to the community for your support, bug reports, and feedback. With your help, Feathers is better than it ever could have been if I were developing it alone. Happy coding!

About Josh Tynjala

Josh Tynjala is a frontend software developer, open source contributor, karaoke enthusiast, and he likes bowler hats. Josh develops Feathers UI, a user interface component library for creative apps, and he is a member of the OpenFL leadership team. One of his side projects is Logic.ly, a digital logic circuit simulator for education. You should follow Josh on Mastodon.

Discussion

Leave a Reply

Your email address will not be published. Required fields are marked *