loading...
Cover image for Refactoring: Classes for Everything?

Refactoring: Classes for Everything?

jwp profile image John Peters Updated on ・3 min read

Our code is a universe of stars all shining in their own way, doing what they do unimpeded.

Functions are Independent!

For those that have come from the OOP world, the "Class" is king; however, in Typescript, the "Class" has a coequal, the "Function".

All functions need to be independent or pure. The parameters are the explicit interface, while the return type never changes.

Pure functions do not mutate input parameters. If we pass in the proper parameters all dependencies are met, the function is then a single independent small unit of work.

Some parameters may be function pointers where other dependencies are satisfied at just the right time.

Unlike C# or Java; however, the Typescript / JavaScript "Function" is a true first class citizen!. Calling the functions do not require a class.

Those that argue that the "Function" is a first class citizen in C# or Java are simply wrong, this includes Microsoft and possibly Oracle.

The Icons Component

Assume we have an Icons Component (Angular,React or Web Component):

  • Has 5 Icons : Create, Edit, Save, Delete and a Checkmark icon.
  • Each fire an event when clicked.
  • Consumer can show or hide any of them.
  • They are contained in a HTML5 grid with auto-width ability.
  • Each can by styled to any color

We create the component and consider it "Done". As in Agile "Done".

It is intentionally small and only does those things.

A New Change Request Arrives

  • Now the user wants the check mark to be able to flash in place of any icon to give feedback to the user. The check mark color can be red or green and the flash time should be adjustable.

Two Ways of Implementation

  • Put the new functionality inside of the Icons Component class.
  • Or put all of the new functionality in a separate Typescript file/module named IconsComponent.ts in a folder named 'functions' .

Which do you think is better? The answer involves following the Open Closed Principle, yes for Typescript too.

The View is done! We are not going to modify that component, unless there is no other option, such as adding a new Icon etc.!

The Icons Component never changes as it is considered 'DONE'. It is closed to modification.

We are going to put all new functionality in a separate Typescript module as one or more functions.

✔️ The Advantage of Function Aggregation

JavaScript modules are simply a file with one or more exports of functions or classes.

  • By aggregating functions, we don't have to import an entire class for just one thing, rather we import just that function from that module! Talking about separation of concerns.

  • Intellisense auto discovers all exportable functions in that module and allows for easy api discovery.

  • If we use naming conventions for each function, finding them via Intellisense is simple.

  • Reusable Views are all about composition, this is a way to compose behaviors while keeping the Views simple. Each consumer has the option to wire up functional behaviors as is needed.

For C# people, this is similar to the concept of an extension method. Not exactly the same and not static or a true extension method that adds functionality to existing types (yet). It is a way to single out a single thing to do a single job and to auto-discover all other functions within that module.

Summary

In Typescript, it's good to keep view classes focused on one and only one simple thing, while providing additional behavioral functions for that class elsewhere. Allow the consumer to import parts instead of Class monoliths.

Keep your runtime stack small, especially when we're talking about reusable components.

JWP2020 Functions are First Class.

Discussion

pic
Editor guide