loading...
Cover image for Refactoring: Functions With View Concerns?

Refactoring: Functions With View Concerns?

jwp profile image John Peters Updated on ・2 min read

This post is further discussion in the Series "Refactoring".

In the prior post, these points were emphasized:

Architectural Goals

  • No Duplicated code ever!
  • One time, One Place, One Concern
  • ~10 to 20 lines of code per Function
  • Input and output are well-known and bulletproof
  • Async First
  • Optional mutation

Today we talk about One Time, Place, and Concern. In particular the Concern part.

Reusable Functions and Views

Should reusable functions concern themselves with the View?

It is not a violation of concerns; in Typescript or Javascript, for functions to have View concerns. While the Angular, React or Vue classes typically deal with the view; true functional first class citizens are at the same level as the class. This means we are easily able to step up the work of the function to co-exist with the view.

Java and C# claim methods are first class citizens. This is a lie, because functions there must live under class definitions. C# does have extension methods but this is not the same thing discussed here.

In fact, there could be an argument (and there is) that we don't need classes at all! However, we didn't design React, Vue or Angular so we are forced into class based inheritance, which is not a bad thing when done correctly. React, Vue and Angular have done it correctly.

In the prior article we learned how to spot "Close Coupling" which is usually bad, simply by looking at all the "this." code. In that article we showed how to refactor by putting that code into new module and replacing all the "this." code with parameters.

Today we go one step further as shown here, which is a specific case for moving View concerns into functions.

export function funcSetPerson(vc: ViewComponent) {
   /** True if existing person, false if newPerson */
   return new Promise<boolean>((resolve, reject) => {
      let personID = funcGetRouteId(vc.ar);
      if (personID > 0) {
         ec.httpService.getPersonByID(personID).subscribe(
            (person) => {
               funcHandlePersonResponse(vc, person);
            },
            (error) => {
               vc.es.OpenError(ErrorModel.Error(error));
               reject(error);
            }
         );
         resolve(true);
      } else {
         resolve(false);
      }
   });
}
Enter fullscreen mode Exit fullscreen mode

Instead of replacing all of the "this." code we simply passed in the ViewComponent itself.

The function is simply: Send HTTP get request if personID is > 0, based on the input route parameters. Otherwise return false.

Warning

By passing in an entire ViewComponent we are re-implementing something generally not considered good; "close coupling". While it's true it's not always good, sometimes as in the drive train to our rear wheels in our car, "close coupling" is good.

Summary

By following our Architectural Goals:

The ViewComponent code is vastly cleaner doing it this way, and we are creating reusable parts which are bulletproof and focus on only one thing. This means we are creating 'composable' software where we can interchange parts, move them around without affecting anything else.

What we aren't doing when using "Close Coupling" (all the code in the view) is allowing other views to benefit from this code. This is why functions work great for Reusable code.

JWP2020 Refactoring II

Discussion

pic
Editor guide