Try   HackMD

Golang Large Function Refactoring

Simple One

FROM (❌)

if (isAlimSick) {
	var isAlimRequiredDoctor = isRequiredAssistanceFromHospital(isSick, alimPaitent);
	if(isAlimRequiredDoctor) {
		var findAllHospitals = GetHospitals(...);
		
		var suitableHospital = GetSuitableHospital(findAllHospitals, alimPaitent);
	
		return suitableHospital;
	}
}

TO (✔)

if (isAlimNotSick) {
	return null;
}


// alim sick

var isAlimRequiredDoctor = isRequiredAssistanceFromHospital(isSick, alimPaitent);

if (!isAlimRequiredDoctor) {
	return null;
}


var findAllHospitals = GetHospitals(...);

var suitableHospital = GetSuitableHospital(findAllHospitals, alimPaitent);

return suitableHospital;

Comparing

Version 1 : Initial

Version 1 Current code is in level 4 nesting. Which is too complex in terms of unit testing.

Our goal is to reduce that code branching or nesting to level 1, by following all the review guides from Golang code review guides by Md. Alim Ul Karim

Level 4 nesting indications

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

package main import ( "fmt" "strings" "github.com/jinzhu/copier" ) func makeFinalTimezone(timezoneNames []TimezoneName, wikiCsv []WikiTimezone) { var finalTimezone []FinalTimezone copier.Copy(&finalTimezone, &wikiCsv) for index, wiki := range wikiCsv { if wiki.TimezoneName == "-" { var foundInNamesByDatabaseName = searchInTimezoneNames(timezoneNames, wiki.DatabaseName) if foundInNamesByDatabaseName == "-" { fmt.Println("Not Found In Timezones for", wiki.DatabaseName) if strings.Contains(wiki.Notes, "Link to") { // Get value from Link To fmt.Println("Get Link to For wiki.DatabaseName", wiki.Notes) // split with Link To searchingFor := strings.TrimSpace(wiki.Notes[7:]) fmt.Println("Split searchingFor ::", searchingFor) var foundInNames = searchInTimezoneNames(timezoneNames, searchingFor) if foundInNames != "-" { finalTimezone[index].TimezoneName = foundInNames } else { foundInWiki := searchInWikiByLinkToNote(wikiCsv, searchingFor) finalTimezone[index].TimezoneName = foundInWiki } } } else { finalTimezone[index].TimezoneName = foundInNamesByDatabaseName } } } fmt.Printf("Field: %+v\n", finalTimezone) writeFinalCSV(finalTimezone) }

Version 2 : Improved

Version 2

package main import ( "fmt" "strings" "github.com/jinzhu/copier" "gitlab.com/evatix-go/localization/cmd/main/constants" ) type InvalidTimezoneInputParameters struct { hasInvalidTimezoneName bool timezoneNames *[]TimezoneName wikiCsv *[]WikiTimezone wiki *WikiTimezone finalTimezone *FinalTimezone finalTimezones *[]FinalTimezone index int } func makeFinalTimezone( timezoneNames *[]TimezoneName, wikiCsv *[]WikiTimezone, ) { var finalTimezones *[]FinalTimezone copier.Copy(&finalTimezones, wikiCsv) for index, wiki := range *wikiCsv { finalTimezone := (*finalTimezones)[index] invalidTimezoneInputParameters := InvalidTimezoneInputParameters{ hasInvalidTimezoneName: hasInvalidTimeZoneName(wiki.TimezoneName), timezoneNames: timezoneNames, wikiCsv: wikiCsv, wiki: &wiki, finalTimezone: &finalTimezone, finalTimezones: finalTimezones, index: index, } ProcessInvalidTimezoneName(&invalidTimezoneInputParameters) } fmt.Printf("Field: %+v\n", finalTimezones) writeFinalCSV(finalTimezones) } func ProcessInvalidTimezoneName( invalidTimezoneInputParameters *InvalidTimezoneInputParameters, ) { var foundInNamesByDatabaseName = searchInTimezoneNames( invalidTimezoneInputParameters.timezoneNames, invalidTimezoneInputParameters.wiki.DatabaseName) if hasValidTimeZoneName(foundInNamesByDatabaseName) { invalidTimezoneInputParameters.finalTimezone.TimezoneName = foundInNamesByDatabaseName } else { // invalid case , foundInNamesByDatabaseName == constants.InvalidEntryWithHyphen fmt.Println("Not Found In Timezones for", invalidTimezoneInputParameters.wiki.DatabaseName) populatedTimezone := GetPopulatedTimezoneNameInTimezone( invalidTimezoneInputParameters.timezoneNames, invalidTimezoneInputParameters.wikiCsv, invalidTimezoneInputParameters.wiki, invalidTimezoneInputParameters.finalTimezone) // here this step is redundant, just calling GetPopulatedTimezoneNameInTimezone // should be suffice, then it is doing some magic, // which requires future investigation on how it is set to the list again // any mistake in understanding could cause lots of hours. // As as result, to keep things simple, always get value and put the updated one // so that it make sense and also goes by the review process, not reassigning to the same variable again. finalTimezones := *invalidTimezoneInputParameters.finalTimezones finalTimezones[invalidTimezoneInputParameters.index] = *populatedTimezone } } // Finds Timezone name using the last part of // Links to keyword and then puts the right // timezone name in the FinalTimezone object and returns it. func GetPopulatedTimezoneNameInTimezone( timezoneNames *[]TimezoneName, wikiCsv *[]WikiTimezone, wiki *WikiTimezone, finalTimezone *FinalTimezone, ) *FinalTimezone { isNotContainsLinkTo := !strings.Contains(wiki.Notes, constants.LinksTo) if isNotContainsLinkTo { // the first rejection case return finalTimezone } // here we are expecting that constants.LinksTo exist // notes contains constants.LinksTo // Get value from Link To fmt.Println("Get Link to For wiki.DatabaseName", wiki.Notes) // split with Link To searchingFor := strings.TrimSpace(wiki.Notes[7:]) fmt.Println("Split searchingFor ::", searchingFor) foundInNames := searchInTimezoneNames(timezoneNames, searchingFor) hasTimezoneName := hasValidTimeZoneName(foundInNames) if hasTimezoneName { finalTimezone.TimezoneName = foundInNames return finalTimezone } foundInWiki := searchInWikiByLinkToNote(*wikiCsv, searchingFor) finalTimezone.TimezoneName = foundInWiki return finalTimezone }

Important Notes

// here this step is redundant, just calling GetTimezoneNameFromLinksToReference
// should be suffice, then it is doing some magic,
// which requires future investigation on how it is set to the list again
// any mistake in understanding could cause lots of hours.
// As as result, to keep things simple, always get value and put the updated one
// so that it make sense and also goes by the review process, not reassigning to the same variable again.

Version 3 : Final Improvements

Version 3
Use return value as best practice to apply all the review parameters.

Here we have at most level 1 nesting.

package main import ( "fmt" "strings" "github.com/jinzhu/copier" "gitlab.com/evatix-go/localization/cmd/main/constants" ) type InvalidTimezoneInputParameters struct { hasInvalidTimezoneName bool timezoneNames *[]TimezoneName wikiCsv *[]WikiTimezone wiki *WikiTimezone finalTimezones *[]FinalTimezone index int } func makeFinalTimezone( timezoneNames *[]TimezoneName, wikiCsv *[]WikiTimezone, ) { finalTimezones := getCopyFromWikiToFinalTimezones(wikiCsv) for index, wiki := range *wikiCsv { invalidTimezoneInputParameters := InvalidTimezoneInputParameters{ hasInvalidTimezoneName: hasInvalidTimeZoneName(wiki.TimezoneName), timezoneNames: timezoneNames, wikiCsv: wikiCsv, wiki: &wiki, finalTimezones: finalTimezones, index: index, } ProcessInvalidTimezoneName(&invalidTimezoneInputParameters) } fmt.Printf("Field: %+v\n", finalTimezones) writeFinalCSV(finalTimezones) } func ProcessInvalidTimezoneName( invalidTimezoneInputParameters *InvalidTimezoneInputParameters, ) { foundInNamesByDatabaseName := searchInTimezoneNames( invalidTimezoneInputParameters.timezoneNames, invalidTimezoneInputParameters.wiki.DatabaseName) index := invalidTimezoneInputParameters.index finalTimezones := *invalidTimezoneInputParameters.finalTimezones finalTimezone := finalTimezones[index] finalTimezone.TimezoneName = GetTimezoneFinalNameInCaseOfInvalid( invalidTimezoneInputParameters, foundInNamesByDatabaseName) // needs to be assigned back finalTimezones[index] = finalTimezone } func getCopyFromWikiToFinalTimezones( fromWikiCsv *[]WikiTimezone) *[]FinalTimezone { var toFinalTimezones []FinalTimezone wikiCopier := *fromWikiCsv // https://github.com/jinzhu/copier // it doesn't work with pointer to pointer directly. copier.Copy(&toFinalTimezones, &wikiCopier) return &toFinalTimezones } func GetTimezoneFinalNameInCaseOfInvalid( invalidTimezoneInputParameters *InvalidTimezoneInputParameters, foundInNamesByDatabaseName string, ) string { if hasValidTimeZoneName(foundInNamesByDatabaseName) { return foundInNamesByDatabaseName } // invalid case , foundInNamesByDatabaseName == constants.InvalidEntryWithHyphen fmt.Println("Not Found In Timezones for", invalidTimezoneInputParameters.wiki.DatabaseName) timeZoneFinalName := GetTimezoneNameFromLinksToReference( invalidTimezoneInputParameters.timezoneNames, invalidTimezoneInputParameters.wikiCsv, invalidTimezoneInputParameters.wiki) return timeZoneFinalName } // Finds Timezone name using the last part of // Links to keyword and then puts the right // timezone name in the FinalTimezone object and returns it. func GetTimezoneNameFromLinksToReference( timezoneNames *[]TimezoneName, wikiCsv *[]WikiTimezone, wiki *WikiTimezone, ) string { isNotContainsLinkTo := !strings.Contains(wiki.Notes, constants.LinksTo) if isNotContainsLinkTo { return constants.InvalidEntryWithHyphen } // here we are expecting that constants.LinksTo exist fmt.Println("Get Link to For wiki.DatabaseName", wiki.Notes) searchingFor := strings.TrimSpace(wiki.Notes[7:]) fmt.Println("Split searchingFor ::", searchingFor) foundInNames := searchInTimezoneNames(timezoneNames, searchingFor) hasTimezoneName := hasValidTimeZoneName(foundInNames) if hasTimezoneName { return foundInNames } foundInWiki := searchInWikiByLinkToNote(*wikiCsv, searchingFor) return foundInWiki }