简体   繁体   中英

Reduce Cyclomatic Complexity in class file with 200 multiple get and set properties

We're refactoring existing code and using sonar to analyze it.

Files feature a considerable number of get and set operators (200 to 300), increasing the file's cyclomatic complexity to 300.

This file has to be refactored to bring the threshold closer to 100.

I tried the following method:

  1. Partial classes do not work since the complexity is determined by the file.
  2. Lifting and shifting properties to many static files isn't going to work because static files can't have props?
  3. Should we think about any design patterns for extracting the prop and initializing it in the constructor?

What is the most efficient way to lower the Cyclomatic Complexity of such files?

Sample Code: 

The class Constructor with all the properties defined in the class

 public BEVehicle()
        {
            this.VehicleID = default(Guid);
            this.VehicleZip = default(string);
            this.VehicleType = default(string);
            this.Year = default(string);
            this.Make = default(string);
            this.Make_Code = default(string);
            this.Model = default(string);
            this.Model_Code = default(string);
            this.Trim_Code = default(string);
            this.VehicleValue = default(string);
            this.GrossVehicleWeight = default(string);
            this.VehicleOwnership = default(string);
            this.DistanceRadius = default(string);
            this.AntiLockBrakes = default(string);
            this.PassiveRestraintSystem = default(string);
            this.AirBags = default(string);

            //// RentedVehicles = default(string);
            //// NonOwned = default(string);
            //// ForHire = default(string);
            //// VehicleFilings = default(string);
            this.Comprehensive = default(string);
            this.Collision = default(string);
            this.Classification = default(string);
            this.ClassificationDetail = new BEClassificationDetail();
            this.CAClassificationDetails = new BECAClassificationDetail();
            this.TrailerToVehicle = default(string);
            this.State = default(string);
            this.StateName = default(string);
            this.City = default(string);
            this.ClassificationCompany = default(string);
            this.CurrentLimits = default(string);
            this.VehicleUse = default(string);
            this.BodyType = default(string);
            this.PersonalUse = default(string);
            this.VehicleWeight = default(string);
            this.WorkerCompensationInsurance = default(string);
            this.VehicleOperatedBy = default(string);
            this.Apartment = default(string);
            this.UnitType = default(string);
            this.StreetAddress = default(string);
            this.ISOVehicleCostNew = default(string);
            this.IsVehicleCarriesGoods = default(string);
            this.IsVehicleCommuteForWorkorShcool = default(string);
            this.IsVehicleCommuteForWorkorSchool = default(string);
            this.IsVehicleForTowing = default(string);
            this.OtherTruckTypeDescription = default(string);
            this.TruckType = default(string);
            this.GoodsPickUpLocation = default(string);
            this.IsVehicleCustomized = default(string);
            this.ValueOfCustomization = default(string);
            this.Zone1 = default(string);
            this.Zone2 = default(string);
            this.SecondaryCode = default(string);
            this.SelectedVehicleType = default(string);
            this.ISOVehicleType = default(string);
            this.DistanceRadiusEntered = default(string);
            this.ISOClassificationDetails = new BEISOClassificationDetail();
            this.IsDumpTrailer = default(string);
            this.PentonVehicleType = default(string);
            this.SICCode = default(string);
            this.SICCodeTitle = default(string);
            this.NicoKickOutReason = default(string);
            this.MinimumGVW = default(string);
            this.MinimumVehicleValue = default(string);
            this.VIN = default(string);
            this.AuxRunning = default(string);
            this.AlarmDiscount = default(string);
            this.AntitheftDeviceinstalled = default(string);
            this.BusinessUse = default(string);
            this.NJInEligible = default(string);
            this.NJInEligibleReason = default(string);
            this.RegisteredOwner = default(string);
            this.RegistrationType = default(string);
            this.PENTONTAB = default(string);
            this.PENTONVEH_TYPE = default(string);
            this.HazardousWaste = default(string);
            this.TypeOfDelivery = default(string);
            this.NumberOfJobsites = default(string);
            this.TowHaulAutos = default(string);
            this.StrVehicleNotListed = default(string);
            this.RegisteredState = default(string);
            this.RegisterInThirtyDays = default(string);
            this.DaysPerWeekRS = default(string);
            this.TripsPerDayRS = default(string);
            this.TransportRideshare = default(bool);
            this.TransportOutsideRideshare = default(bool);
            this.PersonalUseRideshare = default(bool);
            this.Commuting = default(bool);
            this.RSSeatCapacity = default(string);
            this.CommuteMilesRS = default(string);
            this.MilesPerTripRS = default(string);
            this.ActualVehicle = default(string);
            this.SelectedAnnualMileage = default(string);
            this.CalculatedAnnualMileage = default(string);
            this.CalculatedRSMileage = default(string);
            this.CalculatedPersonalMileage = default(string);
            this.CalculatedCommuteMileage = default(string);
            this.OtherFirstname = default(string);
            this.OtherLastname = default(string);
            this.OtherSuffix = default(string);
            this.UninsuredPropertyDamage = default(string);
            this.County = default(string);
            this.VehAddressVerifiedInd = default(string);
            this.VehInEligible = default(string);
            this.VehInEligibleReason = default(string);
            this.PCAVehicleCostNew = default(string);
            this.LienholderForCustomEquipment = default(string);
            this.NonDeductibleGlassCoverage = default(string);
            this.LocationClientId = default(int);
            this.SourceLocationId = default(string);
        }


Individual properties with get and set properties
   /// Gets or sets VehicleOwnership.
        /// </summary>
        /// <value>
        /// The vehicle ownership.
        /// </value>
        [XmlElement(ElementName = "VehicleOwnership", Order = 11)]
        public string VehicleOwnership { get; set; }

        /// <summary>
        /// Gets or sets DistanceRadius.
        /// </summary>
        /// <value>
        /// The distance radius.
        /// </value>
        [XmlElement(ElementName = "DistanceRadius", Order = 12)]
        public string DistanceRadius { get; set; }

        /// <summary>
        /// Gets or sets AntiLockBrakes.
        /// </summary>
        /// <value>
        /// The anti lock brakes.
        /// </value>
        [XmlElement(ElementName = "AntiLockBrakes", Order = 13)]
        public string AntiLockBrakes { get; set; }

        /// <summary>
        /// Gets or sets PassiveRestraintSystem.
        /// </summary>
        /// <value>
        /// The passive restraint system.
        /// </value>
        [XmlElement(ElementName = "PassiveRestraintSystem", Order = 14)]
        public string PassiveRestraintSystem { get; set; }

        /// <summary>
        /// Gets or sets AirBags.
        /// </summary>
        /// <value>
        /// The air bags.
        /// </value>
        [XmlElement(ElementName = "AirBags", Order = 15)]
        public string AirBags { get; set; }

I think the most efficient way is rewrite that huge class in sub classes with part of the properties then your class BEVehicle have properties with sub classe ie:

public class BEVehicleModel
    {
        public string VehicleZip { get; set;} 
        public string VehicleType { get; set;} 
        public string Year { get; set;} 
        public string Make { get; set;} 
        public string Make_Code { get; set;} 
        public string Model { get; set;} 
        public string Model_Code { get; set;} 
        public string Trim_Code { get; set;} 
    }

then in BEVehicle

 public class BEVehicle
    {
        public Guid VehicleId { get; set; }
        public BEVehicleModel VehicleModel { get; set; }

        public BEVehicle()
        {
            //your initialization

        }
    }

Why do you initialize for example strings with default(string) which is null and every string property is already null if you do not touch it. Your code looks more like created by some codegenerator. If it's handwritten I would recommend to remove everthing that does nothing like setting a bool to false or string to null or int to 0. If the code does not change anything in your class it just distracting you from seeing the relevant parts. Your constructor could be shortend to the following without changing the behaviour of your class.

public BEVehicle()
{
  this.ClassificationDetail = new BEClassificationDetail();
  this.CAClassificationDetails = new BECAClassificationDetail();
  this.ISOClassificationDetails = new BEISOClassificationDetail();
}

and you should delete all the comments if the do not add any information that helps understanding the code.

Stating the obvious is distracting instead of helping comments like this should be avoided

// asign value 42 to int
int foo = 42;

and your xml decorations could be made more refactoring save

[XmlElement (ElementName = nameof(VehicleOwnership), Order = 11)]
public string VehicleOwnership { get; set; }

or if the Order is not relevant for you you could change the code to (but strictly speaking that would be more than refactoring because this could change the order in which the elements get serialized)

[XmlElement]
public string VehicleOwnership { get; set; }

So the result is a extremly simple class. If you have rules that prohibit classes like that you should consider changing your rules or at least exclude simple DTOs from complexity checks

The very first signal is about the complexity of your object... 200 properties in one single object is already an indication that something goes wrong.. Aka God object pattern.. an object dealing with far too much stuff..

Quickly parsing these attributes, I can see things related to an address.. Others related to car physical details.. Other like SelectedCarType does not seem at there place at all.

Therefore instead of looking at some language grammar tricks that can shut up sonarqube I would invest time at reshaping this definition into multiple entities.

Like address, car engine specs, transmission type and specs, ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM