কার্যপ্রণালী থেকে অবজেক্ট ওরিয়েন্টড কোডে রূপান্তর করুন


16

আমি লিগ্যাসি কোড এবং ক্লিন কোডের সাথে কার্যকরভাবে পড়তে শুরু করছি যে কীভাবে একটি বৃহত এএসপি.নেট ওয়েবফোর্স অ্যাপ্লিকেশনের বিদ্যমান কোড-বেস পরিষ্কার করতে হবে সে সম্পর্কে কৌশল শেখার লক্ষ্য নিয়ে।

এই ব্যবস্থাটি ২০০৫ সাল থেকে প্রায় হয়েছে এবং তার পর থেকে বেশ কয়েকটি উন্নতি হয়েছে। মূলত কোডটি নিম্নরূপে কাঠামোগত হয়েছিল (এবং এখনও এটি বেশিরভাগভাবে এইভাবে কাঠামোগত করা হয়েছে):

  • এএসপি.এনইটি (এসপেক্স / এসএসএক্স)
  • কোড-পিছনে (সি #)
  • ব্যবসায় যুক্তিযুক্ত স্তর (সি #)
  • ডেটা অ্যাক্সেস স্তর (সি #)
  • ডাটাবেস (ওরাকল)

মূল সমস্যাটি হ'ল কোডটি হ'ল অবজেক্ট-ওরিয়েন্টেড হিসাবে প্রক্রিয়াজাতীয় মাস্ক্রেডিং। এটি কার্যত উভয় বইয়ে বর্ণিত সমস্ত নির্দেশিকা লঙ্ঘন করেছে।

এটি ব্যবসায় লজিক স্তরতে একটি সাধারণ শ্রেণীর উদাহরণ:

    public class AddressBO
{
    public TransferObject GetAddress(string addressID)
    {
        if (StringUtils.IsNull(addressID))
        {
            throw new ValidationException("Address ID must be entered");
        }

        AddressDAO addressDAO = new AddressDAO();
        return addressDAO.GetAddress(addressID);
    }

    public TransferObject Insert(TransferObject addressDetails)
    {
        if (StringUtils.IsNull(addressDetails.GetString("EVENT_ID")) ||
            StringUtils.IsNull(addressDetails.GetString("LOCALITY")) ||
            StringUtils.IsNull(addressDetails.GetString("ADDRESS_TARGET")) ||
            StringUtils.IsNull(addressDetails.GetString("ADDRESS_TYPE_CODE")) ||
            StringUtils.IsNull(addressDetails.GetString("CREATED_BY")))
        {
            throw new ValidationException(
                "You must enter an Event ID, Locality, Address Target, Address Type Code and Created By.");
        }

        string addressID = Sequence.GetNextValue("ADDRESS_ID_SEQ");
        addressDetails.SetValue("ADDRESS_ID", addressID);

        string syncID = Sequence.GetNextValue("SYNC_ID_SEQ");
        addressDetails.SetValue("SYNC_ADDRESS_ID", syncID);

        TransferObject syncDetails = new TransferObject();

        Transaction transaction = new Transaction();

        try
        {
            AddressDAO addressDAO = new AddressDAO();
            addressDAO.Insert(addressDetails, transaction);

            // insert the record for the target
            TransferObject addressTargetDetails = new TransferObject();
            switch (addressDetails.GetString("ADDRESS_TARGET"))
            {
                case "PARTY_ADDRESSES":
                    {
                        addressTargetDetails.SetValue("ADDRESS_ID", addressID);
                        addressTargetDetails.SetValue("ADDRESS_TYPE_CODE",
                                                      addressDetails.GetString("ADDRESS_TYPE_CODE"));
                        addressTargetDetails.SetValue("PARTY_ID", addressDetails.GetString("PARTY_ID"));
                        addressTargetDetails.SetValue("EVENT_ID", addressDetails.GetString("EVENT_ID"));
                        addressTargetDetails.SetValue("CREATED_BY", addressDetails.GetString("CREATED_BY"));

                        addressDAO.InsertPartyAddress(addressTargetDetails, transaction);

                        break;
                    }
                case "PARTY_CONTACT_ADDRESSES":
                    {
                        addressTargetDetails.SetValue("ADDRESS_ID", addressID);
                        addressTargetDetails.SetValue("ADDRESS_TYPE_CODE",
                                                      addressDetails.GetString("ADDRESS_TYPE_CODE"));
                        addressTargetDetails.SetValue("PUBLIC_RELEASE_FLAG",
                                                      addressDetails.GetString("PUBLIC_RELEASE_FLAG"));
                        addressTargetDetails.SetValue("CONTACT_ID", addressDetails.GetString("CONTACT_ID"));
                        addressTargetDetails.SetValue("EVENT_ID", addressDetails.GetString("EVENT_ID"));
                        addressTargetDetails.SetValue("CREATED_BY", addressDetails.GetString("CREATED_BY"));

                        addressDAO.InsertContactAddress(addressTargetDetails, transaction);

                        break;
                    }

                << many more cases here >>
                default:
                    {
                        break;
                    }
            }

            // synchronise
            SynchronisationBO synchronisationBO = new SynchronisationBO();
            syncDetails = synchronisationBO.Synchronise("I", transaction,
                                                        "ADDRESSES", addressDetails.GetString("ADDRESS_TARGET"),
                                                        addressDetails, addressTargetDetails);


            // commit
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            throw;
        }

        return new TransferObject("ADDRESS_ID", addressID, "SYNC_DETAILS", syncDetails);
    }


    << many more methods are here >>

}

এর প্রচুর অনুলিপি রয়েছে, শ্রেণীর অনেকগুলি দায়িত্ব ইত্যাদি রয়েছে ইত্যাদি it এটি কেবল 'আন-ক্লিন' কোড।

সিস্টেম জুড়ে সমস্ত কোডই কংক্রিট বাস্তবায়নের উপর নির্ভরশীল।

এটি ডেটা অ্যাক্সেস লেয়ারের একটি সাধারণ শ্রেণীর উদাহরণ:

    public class AddressDAO : GenericDAO
{
    public static readonly string BASE_SQL_ADDRESSES =
        "SELECT " +
        "  a.address_id, " +
        "  a.event_id, " +
        "  a.flat_unit_type_code, " +
        "  fut.description as flat_unit_description, " +
        "  a.flat_unit_num, " +
        "  a.floor_level_code, " +
        "  fl.description as floor_level_description, " +
        "  a.floor_level_num, " +
        "  a.building_name, " +
        "  a.lot_number, " +
        "  a.street_number, " +
        "  a.street_name, " +
        "  a.street_type_code, " +
        "  st.description as street_type_description, " +
        "  a.street_suffix_code, " +
        "  ss.description as street_suffix_description, " +
        "  a.postal_delivery_type_code, " +
        "  pdt.description as postal_delivery_description, " +
        "  a.postal_delivery_num, " +
        "  a.locality, " +
        "  a.state_code, " +
        "  s.description as state_description, " +
        "  a.postcode, " +
        "  a.country, " +
        "  a.lock_num, " +
        "  a.created_by, " +
        "  TO_CHAR(a.created_datetime, '" + SQL_DATETIME_FORMAT + "') as created_datetime, " +
        "  a.last_updated_by, " +
        "  TO_CHAR(a.last_updated_datetime, '" + SQL_DATETIME_FORMAT + "') as last_updated_datetime, " +
        "  a.sync_address_id, " +
        "  a.lat," +
        "  a.lon, " +
        "  a.validation_confidence, " +
        "  a.validation_quality, " +
        "  a.validation_status " +
        "FROM ADDRESSES a, FLAT_UNIT_TYPES fut, FLOOR_LEVELS fl, STREET_TYPES st, " +
        "     STREET_SUFFIXES ss, POSTAL_DELIVERY_TYPES pdt, STATES s " +
        "WHERE a.flat_unit_type_code = fut.flat_unit_type_code(+) " +
        "AND   a.floor_level_code = fl.floor_level_code(+) " +
        "AND   a.street_type_code = st.street_type_code(+) " +
        "AND   a.street_suffix_code = ss.street_suffix_code(+) " +
        "AND   a.postal_delivery_type_code = pdt.postal_delivery_type_code(+) " +
        "AND   a.state_code = s.state_code(+) ";


    public TransferObject GetAddress(string addressID)
    {
        //Build the SELECT Statement
        StringBuilder selectStatement = new StringBuilder(BASE_SQL_ADDRESSES);

        //Add WHERE condition
        selectStatement.Append(" AND a.address_id = :addressID");

        ArrayList parameters = new ArrayList{DBUtils.CreateOracleParameter("addressID", OracleDbType.Decimal, addressID)};

        // Execute the SELECT statement
        Query query = new Query();
        DataSet results = query.Execute(selectStatement.ToString(), parameters);

        // Check if 0 or more than one rows returned
        if (results.Tables[0].Rows.Count == 0)
        {
            throw new NoDataFoundException();
        }
        if (results.Tables[0].Rows.Count > 1)
        {
            throw new TooManyRowsException();
        }

        // Return a TransferObject containing the values
        return new TransferObject(results);
    }


    public void Insert(TransferObject insertValues, Transaction transaction)
    {
        // Store Values
        string addressID = insertValues.GetString("ADDRESS_ID");
        string syncAddressID = insertValues.GetString("SYNC_ADDRESS_ID");
        string eventID = insertValues.GetString("EVENT_ID");
        string createdBy = insertValues.GetString("CREATED_BY");

        // postal delivery
        string postalDeliveryTypeCode = insertValues.GetString("POSTAL_DELIVERY_TYPE_CODE");
        string postalDeliveryNum = insertValues.GetString("POSTAL_DELIVERY_NUM");

        // unit/building
        string flatUnitTypeCode = insertValues.GetString("FLAT_UNIT_TYPE_CODE");
        string flatUnitNum = insertValues.GetString("FLAT_UNIT_NUM");
        string floorLevelCode = insertValues.GetString("FLOOR_LEVEL_CODE");
        string floorLevelNum = insertValues.GetString("FLOOR_LEVEL_NUM");
        string buildingName = insertValues.GetString("BUILDING_NAME");

        // street
        string lotNumber = insertValues.GetString("LOT_NUMBER");
        string streetNumber = insertValues.GetString("STREET_NUMBER");
        string streetName = insertValues.GetString("STREET_NAME");
        string streetTypeCode = insertValues.GetString("STREET_TYPE_CODE");
        string streetSuffixCode = insertValues.GetString("STREET_SUFFIX_CODE");

        // locality/state/postcode/country
        string locality = insertValues.GetString("LOCALITY");
        string stateCode = insertValues.GetString("STATE_CODE");
        string postcode = insertValues.GetString("POSTCODE");
        string country = insertValues.GetString("COUNTRY");

        // esms address
        string esmsAddress = insertValues.GetString("ESMS_ADDRESS");

        //address/GPS
        string lat = insertValues.GetString("LAT");
        string lon = insertValues.GetString("LON");
        string zoom = insertValues.GetString("ZOOM");

        //string validateDate = insertValues.GetString("VALIDATED_DATE");
        string validatedBy = insertValues.GetString("VALIDATED_BY");
        string confidence = insertValues.GetString("VALIDATION_CONFIDENCE");
        string status = insertValues.GetString("VALIDATION_STATUS");
        string quality = insertValues.GetString("VALIDATION_QUALITY");


        // the insert statement
        StringBuilder insertStatement = new StringBuilder("INSERT INTO ADDRESSES (");
        StringBuilder valuesStatement = new StringBuilder("VALUES (");

        ArrayList parameters = new ArrayList();

        // build the insert statement
        insertStatement.Append("ADDRESS_ID, EVENT_ID, CREATED_BY, CREATED_DATETIME, LOCK_NUM ");
        valuesStatement.Append(":addressID, :eventID, :createdBy, SYSDATE, 1 ");
        parameters.Add(DBUtils.CreateOracleParameter("addressID", OracleDbType.Decimal, addressID));
        parameters.Add(DBUtils.CreateOracleParameter("eventID", OracleDbType.Decimal, eventID));
        parameters.Add(DBUtils.CreateOracleParameter("createdBy", OracleDbType.Varchar2, createdBy));

        // build the insert statement
        if (!StringUtils.IsNull(syncAddressID))
        {
            insertStatement.Append(", SYNC_ADDRESS_ID");
            valuesStatement.Append(", :syncAddressID");
            parameters.Add(DBUtils.CreateOracleParameter("syncAddressID", OracleDbType.Decimal, syncAddressID));
        }

        if (!StringUtils.IsNull(postalDeliveryTypeCode))
        {
            insertStatement.Append(", POSTAL_DELIVERY_TYPE_CODE");
            valuesStatement.Append(", :postalDeliveryTypeCode ");
            parameters.Add(DBUtils.CreateOracleParameter("postalDeliveryTypeCode", OracleDbType.Varchar2, postalDeliveryTypeCode));
        }

        if (!StringUtils.IsNull(postalDeliveryNum))
        {
            insertStatement.Append(", POSTAL_DELIVERY_NUM");
            valuesStatement.Append(", :postalDeliveryNum ");
            parameters.Add(DBUtils.CreateOracleParameter("postalDeliveryNum", OracleDbType.Varchar2, postalDeliveryNum));
        }

        if (!StringUtils.IsNull(flatUnitTypeCode))
        {
            insertStatement.Append(", FLAT_UNIT_TYPE_CODE");
            valuesStatement.Append(", :flatUnitTypeCode ");
            parameters.Add(DBUtils.CreateOracleParameter("flatUnitTypeCode", OracleDbType.Varchar2, flatUnitTypeCode));
        }

        if (!StringUtils.IsNull(lat))
        {
            insertStatement.Append(", LAT");
            valuesStatement.Append(", :lat ");
            parameters.Add(DBUtils.CreateOracleParameter("lat", OracleDbType.Decimal, lat));
        }

        if (!StringUtils.IsNull(lon))
        {
            insertStatement.Append(", LON");
            valuesStatement.Append(", :lon ");
            parameters.Add(DBUtils.CreateOracleParameter("lon", OracleDbType.Decimal, lon));
        }

        if (!StringUtils.IsNull(zoom))
        {
            insertStatement.Append(", ZOOM");
            valuesStatement.Append(", :zoom ");
            parameters.Add(DBUtils.CreateOracleParameter("zoom", OracleDbType.Decimal, zoom));
        }

        if (!StringUtils.IsNull(flatUnitNum))
        {
            insertStatement.Append(", FLAT_UNIT_NUM");
            valuesStatement.Append(", :flatUnitNum ");
            parameters.Add(DBUtils.CreateOracleParameter("flatUnitNum", OracleDbType.Varchar2, flatUnitNum));
        }

        if (!StringUtils.IsNull(floorLevelCode))
        {
            insertStatement.Append(", FLOOR_LEVEL_CODE");
            valuesStatement.Append(", :floorLevelCode ");
            parameters.Add(DBUtils.CreateOracleParameter("floorLevelCode", OracleDbType.Varchar2, floorLevelCode));
        }

        if (!StringUtils.IsNull(floorLevelNum))
        {
            insertStatement.Append(", FLOOR_LEVEL_NUM");
            valuesStatement.Append(", :floorLevelNum ");
            parameters.Add(DBUtils.CreateOracleParameter("floorLevelNum", OracleDbType.Varchar2, floorLevelNum));
        }

        if (!StringUtils.IsNull(buildingName))
        {
            insertStatement.Append(", BUILDING_NAME");
            valuesStatement.Append(", :buildingName ");
            parameters.Add(DBUtils.CreateOracleParameter("buildingName", OracleDbType.Varchar2, buildingName));
        }

        if (!StringUtils.IsNull(lotNumber))
        {
            insertStatement.Append(", LOT_NUMBER");
            valuesStatement.Append(", :lotNumber ");
            parameters.Add(DBUtils.CreateOracleParameter("lotNumber", OracleDbType.Varchar2, lotNumber));
        }

        if (!StringUtils.IsNull(streetNumber))
        {
            insertStatement.Append(", STREET_NUMBER");
            valuesStatement.Append(", :streetNumber ");
            parameters.Add(DBUtils.CreateOracleParameter("streetNumber", OracleDbType.Varchar2, streetNumber));
        }

        if (!StringUtils.IsNull(streetName))
        {
            insertStatement.Append(", STREET_NAME");
            valuesStatement.Append(", :streetName ");
            parameters.Add(DBUtils.CreateOracleParameter("streetName", OracleDbType.Varchar2, streetName));
        }

        if (!StringUtils.IsNull(streetTypeCode))
        {
            insertStatement.Append(", STREET_TYPE_CODE");
            valuesStatement.Append(", :streetTypeCode ");
            parameters.Add(DBUtils.CreateOracleParameter("streetTypeCode", OracleDbType.Varchar2, streetTypeCode));
        }

        if (!StringUtils.IsNull(streetSuffixCode))
        {
            insertStatement.Append(", STREET_SUFFIX_CODE");
            valuesStatement.Append(", :streetSuffixCode ");
            parameters.Add(DBUtils.CreateOracleParameter("streetSuffixCode", OracleDbType.Varchar2, streetSuffixCode));
        }

        if (!StringUtils.IsNull(locality))
        {
            insertStatement.Append(", LOCALITY");
            valuesStatement.Append(", :locality");
            parameters.Add(DBUtils.CreateOracleParameter("locality", OracleDbType.Varchar2, locality));
        }

        if (!StringUtils.IsNull(stateCode))
        {
            insertStatement.Append(", STATE_CODE");
            valuesStatement.Append(", :stateCode");
            parameters.Add(DBUtils.CreateOracleParameter("stateCode", OracleDbType.Varchar2, stateCode));
        }

        if (!StringUtils.IsNull(postcode))
        {
            insertStatement.Append(", POSTCODE");
            valuesStatement.Append(", :postcode ");
            parameters.Add(DBUtils.CreateOracleParameter("postcode", OracleDbType.Varchar2, postcode));
        }

        if (!StringUtils.IsNull(country))
        {
            insertStatement.Append(", COUNTRY");
            valuesStatement.Append(", :country ");
            parameters.Add(DBUtils.CreateOracleParameter("country", OracleDbType.Varchar2, country));
        }

        if (!StringUtils.IsNull(esmsAddress))
        {
            insertStatement.Append(", ESMS_ADDRESS");
            valuesStatement.Append(", :esmsAddress ");
            parameters.Add(DBUtils.CreateOracleParameter("esmsAddress", OracleDbType.Varchar2, esmsAddress));
        }

        if (!StringUtils.IsNull(validatedBy))
        {
            insertStatement.Append(", VALIDATED_DATE");
            valuesStatement.Append(", SYSDATE ");
            insertStatement.Append(", VALIDATED_BY");
            valuesStatement.Append(", :validatedBy ");
            parameters.Add(DBUtils.CreateOracleParameter("validatedBy", OracleDbType.Varchar2, validatedBy));
        }


        if (!StringUtils.IsNull(confidence))
        {
            insertStatement.Append(", VALIDATION_CONFIDENCE");
            valuesStatement.Append(", :confidence ");
            parameters.Add(DBUtils.CreateOracleParameter("confidence", OracleDbType.Decimal, confidence));
        }

        if (!StringUtils.IsNull(status))
        {
            insertStatement.Append(", VALIDATION_STATUS");
            valuesStatement.Append(", :status ");
            parameters.Add(DBUtils.CreateOracleParameter("status", OracleDbType.Varchar2, status));
        }

        if (!StringUtils.IsNull(quality))
        {
            insertStatement.Append(", VALIDATION_QUALITY");
            valuesStatement.Append(", :quality ");
            parameters.Add(DBUtils.CreateOracleParameter("quality", OracleDbType.Decimal, quality));
        }

        // finish off the statement
        insertStatement.Append(") ");
        valuesStatement.Append(")");

        // build the insert statement
        string sql = insertStatement + valuesStatement.ToString();

        // Execute the INSERT Statement
        Dml dmlDAO = new Dml();
        int rowsAffected = dmlDAO.Execute(sql, transaction, parameters);

        if (rowsAffected == 0)
        {
            throw new NoRowsAffectedException();
        }
    }

    << many more methods go here >>
}

এই সিস্টেমটি আমার এবং একটি ছোট দল 2005 সালে 1 সপ্তাহ পরে ফিরে বিকশিত হয়েছিল। নেট কোর্স। এর আগে আমার অভিজ্ঞতা ক্লায়েন্ট-সার্ভার অ্যাপ্লিকেশনগুলিতে ছিল। গত ৫ বছরে আমি স্বয়ংক্রিয় ইউনিট টেস্টিং, স্বয়ংক্রিয় ইন্টিগ্রেশন টেস্টিং এবং স্বয়ংক্রিয় স্বীকৃতি পরীক্ষার (সেলেনিয়াম বা সমতুল্য ব্যবহার করে) সুবিধাগুলি স্বীকৃতি দিতে এসেছি তবে বর্তমান কোড-বেসটি এই ধারণাগুলি প্রবর্তন করা অসম্ভব বলে মনে হচ্ছে।

আমরা এখন শক্ত সময়-ফ্রেম সহ একটি বড় বর্ধন প্রকল্পে কাজ শুরু করছি। এই টিমে 5। নেট বিকাশকারী রয়েছে - 2 বছর বিকাশকারী কয়েক বছর। নেট অভিজ্ঞতা রয়েছে এবং 3 জন খুব কম বা না নেট অভিজ্ঞতা রয়েছে। দলের কোনওেরই (নিজেকে অন্তর্ভুক্ত করে) NET ইউনিট পরীক্ষা বা ফ্রেমওয়ার্কগুলি উপহাস করার অভিজ্ঞতা নেই।

এই কোডটি ক্লিনার, আরও অবজেক্ট-ওরিয়েন্টেড, টেস্টেবল এবং রক্ষণাবেক্ষণযোগ্য করার জন্য আপনি কোন কৌশলটি ব্যবহার করবেন?


9
একদিকে যেমন, এটি দ্বিগুণ পরীক্ষা করা মূল্যবান যে সিস্টেমে পুনর্লিখনের জন্য ব্যয় যুক্তিসঙ্গত রয়েছে। পুরানো কোডটি কুরুচিপূর্ণ হতে পারে তবে এটি যদি যথেষ্ট পরিমাণে কার্যকর হয় তবে রুক্ষ প্রান্তগুলি দিয়ে রাখা এবং আপনার বিকাশের সময় অন্য কোথাও বিনিয়োগ করা সস্তা।
স্মিথকো

একটি সম্ভাব্য যৌক্তিকতা হ'ল প্রতিটি বর্ধন প্রকল্পের পরে ম্যানুয়াল পুনরায় পরীক্ষার প্রচেষ্টা এবং ব্যয় হ্রাস করা। শেষ প্রকল্পের শেষে, ম্যানুয়াল পরীক্ষাটি প্রায় 2 মাস ধরে চলেছিল। যদি আরও স্বয়ংক্রিয় পরীক্ষার প্রবর্তন এই প্রচেষ্টাটি 1-2 সপ্তাহের মধ্যে হ্রাস করে তবে এটি তার পক্ষে উপযুক্ত।
অ্যান্টনি

5
লেগ্যাসি কোডের জন্য, এই জিনিসটি খুব সুন্দর!
কাজ

আমি সম্মত যে যুক্তিসঙ্গতভাবে সামঞ্জস্যপূর্ণ এবং কাঠামোগত। আমার মূল লক্ষ্য পরিবর্তনের পার্শ্ব প্রতিক্রিয়া হ্রাস করা। প্রতিটি প্রকল্পের পরে (এবং সময়কালে) পুরো প্রয়োগটিকে ম্যানুয়ালি পরীক্ষা করার জন্য প্রয়োজনীয় প্রচেষ্টা বিশাল। ক্লায়েন্ট-সাইডের মাধ্যমে এটি পরীক্ষা করার জন্য আমি সেলেনিয়াম ব্যবহার করার কথা ভেবেছিলাম - ডাটাবেসটি দ্রুত ফিরিয়ে আনার বিষয়ে আমার পরামর্শ পেতে সার্ভারফল্ট ( সার্ভারফল্ট / প্রশ্নস / 236546/… ) রয়েছে… আমি মনে করি স্বয়ংক্রিয় গ্রহণযোগ্যতা পরীক্ষার ফলে একটি বিশাল পুনর্লিখন না করে বেশিরভাগ সুবিধা পাওয়া যাবে।
অ্যান্টনি

উত্তর:


16

আপনি দুটি বই উল্লেখ করেছেন যেখানে প্রাথমিক বার্তাগুলির মধ্যে একটি হল "দ্য বয় স্কাউট রুল" অর্থাত্ কোডটি স্পর্শ করার সাথে সাথে পরিষ্কার করুন। আপনার যদি একটি ওয়ার্কিং সিস্টেম থাকে তবে একটি বিশাল পুনর্লিখনটি পাল্টা-উত্পাদনশীল। পরিবর্তে, আপনি নতুন কার্যকারিতা যুক্ত করার সাথে সাথে কোডটি যেমন দাঁড়িয়ে আছে তেমন উন্নতি করে তা নিশ্চিত করুন।

  • আপনার যে পরিবর্তন করতে হবে তা বিদ্যমান কোডটি কভার করতে ইউনিট পরীক্ষা লিখুন।
  • সেই কোডটির রিফ্যাক্টর যাতে এটি পরিবর্তনের জন্য আরও নমনীয় হয় (আপনার পরীক্ষাগুলি এখনও পাস করেছে তা নিশ্চিত করে)।
  • নতুন / সংশোধিত কার্যকারিতা জন্য পরীক্ষা লিখুন
  • নতুন পরীক্ষাগুলি পাস করার জন্য কোড লিখুন
  • প্রয়োজনীয় হিসাবে রিফ্যাক্টর।

আরও ডুব দেওয়ার জন্য, পালকগুলি তার seams এ অ্যাপ্লিকেশনটি পরীক্ষা করার বিষয়ে কথা বলে: ইউনিটগুলি সংযুক্ত হওয়া লজিক্যাল পয়েন্টগুলি। নির্ভরতার জন্য একটি স্টাব বা উপদ্রব তৈরি করতে আপনি একটি সিমের সুবিধা নিতে পারেন যাতে আপনি নির্ভরশীল অবজেক্টের চারপাশে পরীক্ষা লিখতে পারেন। উদাহরণস্বরূপ আপনার ঠিকানা ঠিকানাটি নেওয়া যাক

public class AddressBO
{
    public TransferObject GetAddress(string addressID)
    {
        if (StringUtils.IsNull(addressID))
        {
            throw new ValidationException("Address ID must be entered");
        }

        AddressDAO addressDAO = new AddressDAO();
        return addressDAO.GetAddress(addressID);
    }
}

এড্রেসবিও এবং অ্যাড্রেসএডএও-র মধ্যে একটি স্পষ্ট সীম রয়েছে। আসুন ঠিকানাডাওর জন্য একটি ইন্টারফেস তৈরি করুন এবং নির্ভরতাটিকে ঠিকানাবিওতে ইনজেকশনের অনুমতি দিন।

public interface IAddressDAO
{
  TransferObject GetAddress(addressID);
  //add other interface methods here.
}

public class AddressDAO:GenericDAO, IAddressDAO
{
  public TransferObject GetAddress(string addressID)
  {
    ///implementation goes here
  }
}

এখন আপনি ইঞ্জেকশনের অনুমতি দেওয়ার জন্য আপনার ঠিকানাবিওকে ডাক্তার করুন

public class AddressBO
{
    private IAddressDAO _addressDAO;
    public AddressBO()
    {
      _addressDAO = new AddressDAO();
    }

    public AddressBO(IAddressDAO addressDAO)
    {
      _addressDAO = addressDAO;
    }

    public TransferObject GetAddress(string addressID)
    {
        if (StringUtils.IsNull(addressID))
        {
            throw new ValidationException("Address ID must be entered");
        }
        //call the injected AddressDAO
        return _addressDAO.GetAddress(addressID);
    }
}

এখানে আমরা "দরিদ্রের নির্ভরতা ইনজেকশন" ব্যবহার করছি। আমাদের একমাত্র লক্ষ্যটি সীম ভাঙ্গা এবং আমাদের ঠিকানাবিও পরীক্ষা করার অনুমতি দেওয়া। এখন আমাদের ইউনিট পরীক্ষায় আমরা একটি উপহাস আইএড্রেসডিএও করতে পারি এবং দুটি বস্তুর মধ্যে মিথস্ক্রিয়াটিকে বৈধতা দিতে পারি।


1
আমি সম্মত হই - আমি যখন এই কৌশলটি পড়ি তখন আমার পছন্দ হয়েছিল। আমরা সত্যই কোনও মূল্য যোগ না করে কোড সাফ করতে কয়েক মাস ব্যয় করতে পারতাম। নতুন বৈশিষ্ট্য যুক্ত করার সময় আমাদের কী পরিবর্তন করতে হবে তা পরিষ্কার করার দিকে যদি আমরা মনোনিবেশ করি তবে আমরা উভয় বিশ্বের সেরা পাই।
অ্যান্টনি

একমাত্র চ্যালেঞ্জটি বিদ্যমান কোডের ইউনিট পরীক্ষাগুলি লেখা। আমি প্রথমে আরও উচ্চ-স্তরের পরীক্ষার দিকে ঝুঁকছি যাতে আমরা আরও বেশি আত্মবিশ্বাসের সাথে ইউনিট পরীক্ষা যুক্ত করতে পারি।
অ্যান্টনি

1
হ্যাঁ আপনি যা করতে পারেন তার মধ্যে সবচেয়ে ভাল পরীক্ষা করা যা কোড যাচাই করে তা যা যা করে তা যাচাই করে। আপনি সঠিক আচরণ যাচাই করে এমন পরীক্ষা তৈরির চেষ্টা করতে পারেন ... তবে আপনি অন্যান্য কার্যকারিতা ভঙ্গ করার ঝুঁকি চালান যা পরীক্ষাগুলির আওতায় নেই।
মাইকেল ব্রাউন

পালকগুলিকে অনুশীলনে "সিম সন্ধান করুন" রাখার জন্য এটি আমি সেরা ব্যাখ্যাটি দেখেছি। OO- র চেয়ে বেশি পদ্ধতিগত বিষয়ে কেউ দক্ষ হিসাবেওওর অ্যাড্রেসবিও এবং অ্যাড্রেসডাও-র মধ্যে একটি স্পষ্ট সীম আমার কাছে স্পষ্ট ছিল না, তবে এই উদাহরণটি সত্যই সহায়তা করে।
SeraM

5

যদি আমি মনে করি লেগ্যাসি কোডের সাথে কার্যকরভাবে কাজ করা কাজটি পুনর্লিখনের সাথে সম্পূর্ণরূপে গ্যারান্টি দেয় না যে নতুন কোডটি পুরানো (কার্যকারিতা / ত্রুটির দৃষ্টিকোণ থেকে) এর চেয়ে ভাল হবে। বাগ ঠিক করার সময় / নতুন বৈশিষ্ট্য যুক্ত করার সময় সেই বইয়ের রিফ্যাক্টরিংগুলি।

অন্য একটি বই আমি সুপারিশ করবো হ'ল। নেট মধ্যে ব্রাউনফিল্ড অ্যাপ্লিকেশন ডেভলপমেন্ট যা মূলত পুনর্লিখনের জন্য পুরোপুরি কাজ না করার কথা বলে। আপনি যখনই নতুন বৈশিষ্ট্য যুক্ত করেন বা ত্রুটিগুলি সংশোধন করেন এটি স্থির, পুনরাবৃত্তি পরিবর্তন করার বিষয়ে কথা বলে। এটি ব্যয়ের তুলনায় সুবিধাগুলির বিবেচনার বিষয়গুলি সম্বোধন করে এবং একবারে খুব বেশি বিট করার চেষ্টা করার বিষয়ে সতর্ক করে। যদিও কার্যকরীভাবে উত্তরাধিকার কোড নিয়ে কাজ কীভাবে মাইক্রো / কোড স্তরের উপর refactor করতে, বেশিরভাগ আলোচনা .NET মধ্যে Brownfield এপ্লিকেশন ডেভেলপমেন্ট বেশিরভাগই উচ্চ স্তরের বিবেচনার জুড়ে যখন পুনরায় ফ্যাক্টরিং (কিছু কোড পর্যায়ের কাপড় সহ খুব)।

ব্রাউনফিল্ড বইটি কোডটির কোন ক্ষেত্রটি আপনাকে সবচেয়ে বেশি সমস্যা তৈরি করছে এবং সেখানে দৃষ্টি নিবদ্ধ করছে তা নির্ধারণ করার পরামর্শও দেয়। অন্য যে কোনও ক্ষেত্রের জন্য খুব বেশি রক্ষণাবেক্ষণের দরকার নেই এটি পরিবর্তনযোগ্য নয়।


নেট থেকে ব্রাউনফিল্ড অ্যাপ্লিকেশন ডেভলপমেন্ট বইটির জন্য +1
গ্যাব্রিয়েল মনজিওন

বইয়ের সুপারিশের জন্য ধন্যবাদ - আমি এটি একবার দেখব। সংক্ষিপ্ত বিবরণ থেকে এটি .NET- এ বেশি মনোনিবেশ করা হবে বিশেষত আমি যে দুটি বইয়ের উল্লেখ করেছি তাতে সি, সি ++ এবং জাভাতে ফোকাস বলে মনে হচ্ছে than
অ্যান্টনি

4

এই জাতীয় লিগ্যাসি অ্যাপ্লিকেশনটির জন্য, এটি ইউনিট পরীক্ষার পরিবর্তে (স্বয়ংক্রিয়) উচ্চ স্তরের ইন্টিগ্রেশন পরীক্ষার সাথে আচ্ছাদন করে আরম্ভ করা অনেক বেশি সাশ্রয়ী। তারপরে আপনার সুরক্ষা নেট হিসাবে ইন্টিগ্রেশন টেস্টগুলির সাহায্যে, আপনি যদি যথাযথ হয় তবে ছোট পদক্ষেপগুলিতে রিফ্যাক্টরিং শুরু করতে পারেন , অর্থাত্ যদি রিফেক্টরিংয়ের ব্যয় দীর্ঘ মেয়াদে নিজেকে পরিশোধ করে। অন্যরা যেমন উল্লেখ করেছে, এটি স্বতঃসিদ্ধ নয়।

একই প্রশ্নের জন্য আমার এই পূর্বের উত্তরটিও দেখুন ; আশা করি আপনি এটি দরকারী পাবেন।


আমি শুরু করার জন্য উচ্চ স্তরের পরীক্ষার দিকে ঝুঁকছি। আমি প্রতিটি পরীক্ষার মৃত্যুদণ্ড কার্যকর করার পরে ডাটাবেসটিকে ফিরিয়ে দেওয়ার সর্বোত্তম উপায়ে কাজ করার জন্য ডিবিএর সাথে কাজ করছি।
অ্যান্টনি

1

চলমান কোডটি ফেলে দেওয়া এবং পুনর্লিখনের সাথে খুব সতর্কতা অবলম্বন করুন (যে জিনিসগুলি আপনার কখনও করা উচিত নয় )। অবশ্যই এটি কুরুচিপূর্ণ হতে পারে তবে এটি যদি কাজ করে তবে এটি হয়ে যায়। জোয়েলের ব্লগ পোস্টটি দেখুন, এটির 10+ বছর পুরানো নিশ্চিত, তবে এটি এখনও লক্ষ্যমাত্রায় সঠিক।


আমি সেখানে জোয়েলের সাথে একমত নই। তিনি যা বলেছিলেন সে সময় সম্ভবত এটি প্রাসঙ্গিক মনে হয়েছে তবে এখনকার মোজিলা ফায়ারফক্স নামে পরিচিতিটি কি এটি পুনরায় লিখন নয়?
ক্যাশকো

1
হ্যাঁ, তবে এটি প্রক্রিয়াতে নেটস্কেপকে ব্যবসায়ের বাইরে ফেলেছে! এটি বলছে না যে ওভার শুরু করা কখনই সঠিক পছন্দ নয় তবে এর সম্পর্কে খুব সতর্কতা অবলম্বন করা উচিত। এবং ওও কোডটি সবসময় প্রসেসালাল কোডের থেকে ভাল হয় না।
জাচারি কে

1

মাইক যেমন বলেছিল যে 'বয় স্কাউট রুল' সম্ভবত এখানে সবচেয়ে ভাল, যদি কোডটি কাজ করে এবং বাগ রিপোর্টের ধ্রুবক উত্স না হয় তবে আমি এটি সেখানে বসে থাকতে চাই এবং সময়ের সাথে ধীরে ধীরে এটি উন্নত করতে চাই।

আপনার বর্ধন প্রকল্পের সময় জিনিসগুলির নতুন উপায়ে অনুমতি দিন। উদাহরণস্বরূপ নতুন বৈশিষ্ট্যগুলির জন্য একটি ওআরএম ব্যবহার করুন এবং বিদ্যমান ডেটা স্তর প্যাটার্নটিকে বাইপাস করুন। আপনি যখন বিদ্যমান বর্ধিত কোডগুলিতে স্পর্শ করার প্রয়োজন বর্ধনে চলেছেন তখন আপনি কিছু সম্পর্কিত কোডকে কিছু করার নতুন পদ্ধতিতে সরিয়ে নিতে সক্ষম হতে পারেন। জায়গায় ফ্যাকাস বা কিছু অ্যাডাপ্টার ব্যবহার করা আপনাকে পুরানো কোডটি বিচ্ছিন্ন করতে সহায়তা করতে পারে, এমনকি প্রতি স্তর প্রতি এমনকি। এটি আপনাকে সময় দিয়ে পুরানো কোডটি অনাহারে রাখতে সহায়তা করতে পারে।

একইভাবে এটি ইউনিট পরীক্ষা যোগ করতে আপনাকে সহায়তা করতে পারে, আপনি তৈরি নতুন কোড দিয়ে শুরু করতে পারেন এবং ধীরে ধীরে আপনাকে নতুন বর্ধনের জন্য স্পর্শ করতে হবে এমন পুরানো কোডের জন্য কিছু পরীক্ষা যুক্ত করতে পারেন।


1

সে দুটোই ভাল বই। আপনি যদি সেভাবে পুনরায় লেখার কোডটি শুরু করতে চান তবে আমি মনে করি এটি পুনরায় লেখার সাথে সাথে স্থিতিশীল রাখতে কোডটিকে ইউনিট পরীক্ষার সাহায্যে কভার করাও জরুরী think

এটি ছোট পদক্ষেপে করতে হবে এবং সেই ধরণের কোডটি সংশোধন করা সহজেই পুরো সিস্টেমকে অস্থিতিশীল করতে পারে।

আপনি সক্রিয়ভাবে কাজ করছেন না এমন কোনও কোড আমি সংশোধন করব না। আপনি সক্রিয়ভাবে বর্ধিত বা ফিক্সিংয়ের কোডটিতে এটি করুন। যদি কিছু এটির উদ্দেশ্যে পরিবেশন করে তবে বছরগুলিতে কোনও পরিবর্তন করা হয়নি তবে কেবল এটি ছেড়ে দিন। আপনি যদি আরও ভাল উপায় জানেন তবে এটি এটি করছে।

দিন শেষে সংস্থার উত্পাদনশীলতা প্রয়োজন। যদিও আরও ভাল কোড উত্পাদনশীলতার পুনর্লিখনের কোডটি বাড়ায় কেবল কারণেই এটি আরও ভাল লেখা যেতে পারে সম্ভবত আপনার পণ্যের মূল্য আনার সর্বোত্তম উপায় নয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.