2008-10-24 1 views
2

최근에 I made a post about the developers I'm working with not using try catch blocks properly, 그리고 불행히도 try ... catch 블록을 사용하여 중요한 상황에서 예외 오류를 모두 무시했습니다. 나에게 큰 심장 통증을 유발했다.일반 비즈니스 객체 관행 (및 예외 오류 - redux)

public void AddLocations(BOLocation objBllLocations) 
{ 
    try 
    { 
     dbManager.Open(); 
     if (objBllLocations.StateID != 0) 
     { 
      // about 20 Paramters added to dbManager here 
     } 
     else 
     { 
      // about 19 Paramters added here 
     } 
     dbManager.ExecuteNonQuery(CommandType.StoredProcedure, "ULOCATIONS.AddLocations"); 
    } 
    catch (Exception ex) 
    { 
    } 
    finally 
    { 
     dbManager.Dispose(); 
    } 
} 

이 내 눈에, 절대적으로 discusting이며, 통지하지 않습니다 여기에 그들이 이런 짓을 코드의 수천 섹션 중 하나 (일부 코드가 particuarly 중요하지 않습니다 그 탈락의 예입니다 사용자가 몇 가지 잠재적 인 문제가 발생했을 경우를 대비 한 것입니다. 많은 사람들이 OOP가 좋지 않다고 말합니다. 여러 레이어를 추가하면 코드 줄 수와 프로그램 복잡성이 추가되어 코드 유지 관리와 관련된 문제가 발생할 수 있습니다. 프로그래밍 배경, 나는 개인적으로이 분야에서 거의 같은 접근법을 택했다. 아래에 나는 그런 상황에서 내가 일반적으로 코딩하는 방식의 기본 구조를 나열했다. 나는 내 경력에서이 언어를 여러 언어로 사용 해왔다. 이 특정 코드는 C#에 있습니다. 그러나 아래 코드는 어떻게하면 객체를 사용하면 나에게 도움이되는 것처럼 보일지 모르지만, 이것은 꽤 지루한 프로그래밍 광산의 좋은 원천이기 때문에 오랫동안 사용해 온이 기법을 재평가해야 하는지를 알고 싶습니다. 주로, 앞으로 몇 주 안에, 나는 아웃소싱 된 개발자의 좋은 코드가 아니라 코드의 거대한 부분을 수정하려고합니다. 나는 가능한 한 그것을하고 싶습니다. 긴 코드 참조에 대해 사과드립니다.

// ******************************************************************************************* 
/// <summary> 
/// Summary description for BaseBusinessObject 
/// </summary> 
/// <remarks> 
/// Base Class allowing me to do basic function on a Busines Object 
/// </remarks> 
public class BaseBusinessObject : Object, System.Runtime.Serialization.ISerializable 
{ 
    public enum DBCode 
    { DBUnknownError, 
     DBNotSaved, 
     DBOK 
    } 

    // private fields, public properties 
    public int m_id = -1; 
    public int ID { get { return m_id; } set { m_id = value; } } 
    private int m_errorCode = 0; 
    public int ErrorCode { get { return m_errorCode; } set { m_errorCode = value; } } 
    private string m_errorMsg = ""; 
    public string ErrorMessage { get { return m_errorMsg; } set { m_errorMsg = value; } } 
    private Exception m_LastException = null; 
    public Exception LastException { get { return m_LastException; } set { m_LastException = value;} } 

    //Constructors 
    public BaseBusinessObject() 
    { 
     Initialize(); 
    } 
    public BaseBusinessObject(int iID) 
    { 
     Initialize(); 
     FillByID(iID); 
    } 
    // methods 
    protected void Initialize() 
    { 
     Clear(); 
     Object_OnInit(); 
     // Other Initializable code here 
    } 
    public void ClearErrors() 
    { 
     m_errorCode = 0; m_errorMsg = ""; m_LastException = null; 
    } 

    void System.Runtime.Serialization.ISerializable.GetObjectData(
     System.Runtime.Serialization.SerializationInfo info, 
     System.Runtime.Serialization.StreamingContext context) 
    { 
     //Serialization code for Object must be implemented here 
    } 
    // overrideable methods 
    protected virtual void Object_OnInit()  
    { 
     // User can override to add additional initialization stuff. 
    } 
    public virtual BaseBusinessObject FillByID(int iID) 
    { 
     throw new NotImplementedException("method FillByID Must be implemented"); 
    } 
    public virtual void Clear() 
    { 
     throw new NotImplementedException("method Clear Must be implemented"); 
    } 
    public virtual DBCode Save() 
    { 
     throw new NotImplementedException("method Save Must be implemented"); 
    } 
} 
// ******************************************************************************************* 
/// <summary> 
/// Example Class that might be based off of a Base Business Object 
/// </summary> 
/// <remarks> 
/// Class for holding all the information about a Customer 
/// </remarks> 
public class BLLCustomer : BaseBusinessObject 
{ 
    // *************************************** 
    // put field members here other than the ID 
    private string m_name = ""; 
    public string Name { get { return m_name; } set { m_name = value; } } 
    public override void Clear() 
    { 
     m_id = -1; 
     m_name = ""; 
    } 
    public override BaseBusinessObject FillByID(int iID) 
    { 
     Clear(); 
     try 
     { 
      // usually accessing a DataLayerObject, 
      //to select a database record 
     } 
     catch (Exception Ex) 
     { 
      Clear(); 
      LastException = Ex; 
      // I can have many different exception, this is usually an enum 
      ErrorCode = 3; 
      ErrorMessage = "Customer couldn't be loaded"; 
     } 
     return this; 
    } 
    public override DBCode Save() 
    { 
     DBCode ret = DBCode.DBUnknownError; 
     try 
     { 
      // usually accessing a DataLayerObject, 
      //to save a database record 
      ret = DBCode.DBOK; 
     } 
     catch (Exception Ex) 
     { 
      LastException = Ex; 
      // I can have many different exception, this is usually an enum 
      // i do not usually use just a General Exeption 
      ErrorCode = 3; 
      ErrorMessage = "some really weird error happened, customer not saved"; 
      ret = DBCode.DBNotSaved; 
     } 
     return ret; 
    } 
} 
// ******************************************************************************************* 
// Example of how it's used on an asp page.. 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     // Simplifying this a bit, normally, I'd use something like, 
     // using some sort of static "factory" method 
     // BaseObject.NewBusinessObject(typeof(BLLCustomer)).FillByID(34); 
     BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34); 
     if (cust.ErrorCode != 0) 
     { 
      // There was an error.. Error message is in 
      //cust.ErrorMessage 
      // some sort of internal error code is in 
      //cust.ErrorCode 

      // Give the users some sort of message through and asp:Label.. 
      // probably based off of cust.ErrorMessage 
      //log can be handled in the data, business layer... or whatever 
      lab.ErrorText = cust.ErrorMessage; 
     } 
     else 
     { 
      // continue using the object, to fill in text boxes, 
      // literals or whatever. 
      this.labID = cust.ID.toString(); 
      this.labCompName = cust.Name; 
     } 
    } 

결론은, 내 질문에, 나는 이상 muliple 층으로 일을 복잡하게하고 있는가, 그리고 상속 된 클래스 또는 나의 오래된 개념은 좋은 안정적인 작동 여전히 예시되어있다? 이 일을 성취 할 더 좋은 방법이 있습니까? 동료 작업 동료가 제안한 것처럼 asp.net 페이지 코드에서 곧바로 SQL 호출을 수행해야할까요? (비록 마지막 솔루션을 사용하면 나에게 기분이 상쾌해진다.) 대신 비즈니스 객체와 데이터 레이어 (데이터 레이어 표시되지만 기본적으로 저장된 모든 proc 호출을 보유합니다). 그래, 다른 개발자가 왜 물건을 쌓아 올리려고하는지 물어 보았다. * .aspx.cs 코드 숨김 페이지에 바로 필요한 것을 입력하면 1k 줄 넘는 코드의 기쁨을 누릴 수있다. 뒤에. 여기에 어떤 조언이 있습니까?

답변

1

NHibernate와 같은 ORM을 사용 해본 적이 있습니까? 바퀴를 다시 발명 할 필요는 없습니다.

BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34); 

너무 많은 괄호 : 나 여기에

는 코드 냄새입니다!

C#과 같은 언어에서 활성 레코드 패턴을 사용하면 항상 단위 테스트가 어렵 기 때문에 항상 눈물을 흘리는 것으로 나타났습니다.

+0

죄송합니다. 나는 다른 언어로 영향력을 보여주고있다. – stephenbayer

0

그냥 Page_Load 이벤트에서 예외를 잡아 내지 않는 이유는 무엇입니까? 일부 예외는 예상 할 수 있고 처리 방법을 알고 있지만 다른 예외는 전역 예외 처리기로 처리해야합니다.

1

코드의 첫 번째 비트에서 다음 비트로 건너 뛰는 것이 엄청납니다. 복잡한 비즈니스 객체 계층이 필요한지 여부는 해당 앱의 크기에 따라 달라집니다. 적어도 우리의 정책은 예외가 처리되는 위치에 기록된다는 것입니다. 사용자에게 선물하는 방법은 개발자가 필요에 따라 더 많은 정보를 얻을 수 있도록 당신에게 달려 있지만 로그가 있어야합니다.

0

내 경험에 비추어 볼 때, 내가 처리 할 수있는 오류를 잡거나 사용자에게 유용한 것을 제공하기 만하면됩니다. 그래서 그들이 다시 한 일이라면 다시 할 수 있습니다. 나는 데이터베이스 예외를 잡는다; 그러나 사용되는 데이터에 대한 오류에 대해 더 많은 정보를 추가해야합니다. 그럼 다시 던져. 일반적으로 오류를 처리하는 가장 좋은 방법은 UI 스택 맨위의 어디에서나 오류를 잡아 내지 않는 것입니다.한 페이지 만 있으면 오류를 처리하고 global.asax를 사용하여 거의 모든 상황을 처리 할 수 ​​있습니다. 상태 코드를 사용하는 것은 전혀 스타일이 다릅니다. 그것은 COM의 잔재입니다.

0

구체적인 클래스 대신 추상적 인 기본 클래스를 사용할 수 있습니까? 이것은 런타임 예외가 아닌 개발시에 메소드의 구현을 강요합니다.

여기에 동의하는 가장 좋은 의견은 춤에서 나옵니다. 여기서 그 곳에서 복구 할 수있는 예외 만 처리해야합니다. 다른 사람들을 잡아서 재실행하는 것이 가장 좋은 방법입니다. 또한, 그들이 기록되었는지 확인하십시오 .... :)

0

당신의 오류 처리 방식은 매우 오래된 것 같습니다. 그냥 새로운 예외를 만들고 예외로부터 상속받습니다. 적어도 콜 스택이 있어야합니다. 그런 다음 nlog 또는 log4net과 같이 로그인해야합니다. 그리고 이것은 2008 년이므로 제네릭을 사용하십시오. 그런 식으로 주조하는 횟수를 줄여야합니다.

누군가가 전에 말했듯이 ORM을 사용합니다. 바퀴를 재발 명하려고하지 마십시오.

+0

좋은 점이 있지만 2008 년 논평은 냉소적으로 들린다. –