달력

012008  이전 다음

  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
프로젝트를 진행하다보면 다른 사람들과 많은 이야기를 나눕니다.

업무파악, 개발, 테스트, 납품 등 모든 요소들이 사람에 의해 이루어지고 사람과 대화를 통해 이루어집니다.
대화라는 것은 그 사람이 가진 이론적, 경험적 지식의 총체적 요소의 결과라고 생각합니다.

대화의 상대가 비슷한 파워를 가지는 경우 토론이나 생산적 토론이 가능하지만, 힘의 불균형이 이뤄지는 상대와의 토론은 이론적, 경험적 지식을 무시한채 힘 없는 사람이 잘난채 하는 사람으로 비춰질 가능성이 큽니다.
그리고 언제나 그렇듯 결과는 피를 줄줄 흘리던가 아님 그냥 따라가는 거죠.

힘(물론 힘도 힘 나름이지만...)에 의한 결정... 결코 합리적인 결정이라고 볼 수 없죠.

설사 토론을 하는 분위기가 된다하더라도 대부분 감정적인 싸움으로 끝나게 됩니다.
이성보다는 감정이 앞서는 상황에서 적극적 토론이란 있을 수 없으며, 결국 커뮤니케이션이 잘 될수가 없다고 봅니다. 오늘도 우리는 조직내에서 수많은 이견과 충돌하게 됩니다.

조직상의 서열이나 라인, 직함에 얽매여서 당신도 포크레인 보다는 삽을 추천하십니까?
일은 자존심이 아니라 효율입니다. 프로세스구요...ㅎㅎ

땅을 빨리 팔려면 삽보다는 포크레인이 좋습니다.^^
크리에이티브 커먼즈 라이선스
Creative Commons License

'General Tech.' 카테고리의 다른 글

컴퓨터의 기본구조  (0) 2008/02/12
T-Sql, sp_who에 관한 링크  (0) 2008/02/01
땅을 팔려면 포크레인으로~  (0) 2008/01/29
WBS(Work Breakdown Structure)  (0) 2008/01/29
ADO.NET 표준사례  (0) 2008/01/09
Bill Gates 2008 CES Keynote Speech Part 4  (0) 2008/01/08
Posted by -세티-
WBS(Work Breakdown Structure)
- 프로젝트에서 가장 중요한 시점
- Scope Definition의 주요 Output임.
- Deliverable을 일일이 쪼개야 하는 작업.
- 유사한 것 CWBS, OBS, RBS, BOM, PBS

CWBS(계약 WBS) - 판매자가 구매자에게 제공할 보고수준의 정의를 위해 사용.
OBS(조직분류체계) - 어떤 작업요소가 어떤 조직단위에 배당되었는지를 보여주기 위한 것.
RBS(자원분류체계) - OBS의 변종이고, 통상 작업요소들이 개인에게 할당될 때 사용.
BOM(자재 수량서) - 공장 제작된 생산품을 조립하는데 필요한 물리적인 조립재, 하위조립재, 구성부품 등에
                             대한 위계를 보여준다.
PBS(프로젝트 분류체계) - 올바르게 행해진 WBS와 근본적으로 동일하다.
크리에이티브 커먼즈 라이선스
Creative Commons License

'General Tech.' 카테고리의 다른 글

T-Sql, sp_who에 관한 링크  (0) 2008/02/01
땅을 팔려면 포크레인으로~  (0) 2008/01/29
WBS(Work Breakdown Structure)  (0) 2008/01/29
ADO.NET 표준사례  (0) 2008/01/09
Bill Gates 2008 CES Keynote Speech Part 4  (0) 2008/01/08
2008 CES Keynote 'Bill Gates'  (0) 2008/01/08
Posted by -세티-

 

 

===2007년 제2회 천문노트 정기관측회 영상 + 2008년 홍보_정재원운영진作===

 

 

행사일정

추진항목

세부추진내용

날짜

시간

2월 2일

14 : 30

도착

도착, 인원정리 및 방 배정

15 : 10

~

15 : 30

소개

강당 : 일정 안내, 운영진 인사

15 : 30

~

17 : 00

세미나 1

강당 : 로켓 세미나 및 화약로켓 제작

17 : 00

~

18 : 00

저녁식사

식당

18 : 00

~

18 : 50

세미나 2

강당 : 천체망원경 (박종현)

세미나실 : 천체사진촬영 (김태욱)

19 : 00

~

19 : 20

세미나 3

강당 : Astroview, Astrodraw 시연 (유환용)

19 : 20

~

20 : 10

세미나 4

강당 : 별자리 및 관측대상 소개 (장형규)

20 : 30

~

22 : 30

관측

별자리 (유환용, 장형규) / 사진촬영 (김태욱)

행성 및 딥스카이 관측 (유환용, 박종현)

23 : 00

취침

 

 

~

자유관측

 

2월3일

08 : 00

기상

기상 및 세면

08 : 30

~

09 : 30

아침식사

식당

09 : 30

~

10 : 20

세미나 5

강당 : 우주의학 (이형철)

세미나실 : 항성의 진화 (송용준)

10 : 30

~

11 : 50

OX퀴즈

강당 : 천문노트 소개, OX퀴즈, 설문조사

12 : 00

~

13 : 00

점심식사

식당

13 : 00

숙소 정리

13 : 30

~

14 : 20

실외활동

로켓 발사 및 기념 촬영

14 : 20

귀가

인원점검 및 해산

 

* 세미나 일정은 강사 사정에 따라서 변경이 될 수 있습니다.

** 식사 시간은 수련관 배식시간에 따라서 변경이 될 수 있습니다.

*** 세미나2와 세미나5는 분반하여 진행합니다. 원하시는 세미나를 선택하여 이동하시면 됩니다. 안내해 드립니다.

 

신청하시기 전 꼭 기억하세요.

관측회 참가비 입니다.

초등학생 2만5천원, 중학생 이상(성인 포함) 3만원 입니다.

단체버스를 신청하신 별님께서는 20,000원을 더 지불하셔야 합니다.(서울/경기 부근만 해당)

 

입금기한 및 환불규정
입금기한 : 1월 28일까지(월요일)

ㅇ 1월 28일까지 환불 신청시 : 100 %

ㅇ 1월 30일까지 환불 신청시 : 50 %

ㅇ 1월 31일부터 환불 신청시 : 환불 불가

무통장 입금 하실분 또는 환불등 기타 문의가 있으신 분은 이곳을 참고해주시기 바랍니다.

관측회 문의 게시판 주소 (http://2008.astronote.org)

 

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-
벌써 10년이 넘은 노래가 되었네요.
참 좋아하던 노래였지요.
자꾸자꾸 들어도 지겹지 않은 몇 안되는 노래인데 말이에요...^^

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-

using System;

using System.IO;

using System.IO.Ports;

using System.Threading;

namespace SerialPortTest

{   

             class EntryPoint   

             {      

                           static SerialPort m_com1 = new SerialPort();      

                           static SerialPort m_com2 = new SerialPort();      

                           static string m_com1Data=string.Empty;      

                           static string m_com2Data=string.Empty;      

                           [STAThread]      

                           static void Main(string[] args)      

                           {          // Assigning values for com ports         

                                        m_com1.PortName = "COM1";         

                                        m_com2.PortName = "COM2";         

                                        m_com1.ReceivedBytesThreshold = 1;         

                                        m_com2.ReceivedBytesThreshold = 1;         

                                        m_com1.BaudRate = 115200;         

                                        m_com2.BaudRate = 115200;         

                                        m_com1.DtrEnable = true;         

                                        m_com2.DtrEnable = true;         

                                        m_com1.ReceivedEvent += new SerialEventHandler(OnCom1Receive);         

                                        m_com2.ReceivedEvent += new SerialEventHandler(OnCom2Receive);         

                                        m_com1.Open();         

                                        m_com2.Open();          // create writing threads and start them         

                                        ThreadStart ts = new ThreadStart(BeginWriteCom1);         

                                        Thread t = new Thread(ts);         

                                        t.Start();         

                                        ThreadStart ts2 = new ThreadStart(BeginWriteCom2);         

                                        Thread t2 = new Thread(ts2);         

                                        t2.Start();          // wait for a bit... and then hit enter to exit         

                                        System.Threading.Thread.Sleep(1000);         

                                        Console.Read();      

                           }      

 

                           static private void BeginWriteCom1()      

                          {         

                                        m_com1.Write("Written to Com1 1/3.\n");         

                                        m_com1.Write("Written to Com1 2/3.\n");         

                                        m_com1.Write("Written to Com1 3/3.\n");      

                           }      

 

                           static private void BeginWriteCom2()      

                           {         

                                        m_com2.Write("Written to Com2 1/3\n");         

                                        m_com2.Write("Written to Com2 2/3\n");         

                                        m_com2.Write("Written to Com2 3/3\n");      

                           }                

 

                           static private void OnCom1Receive(object sender, SerialEventArgs e)      

                           {         

                                        Console.WriteLine(m_com1.ReadAvailable());      

                           }      

 

                           static private void OnCom2Receive(object sender, SerialEventArgs e)      

                           {         

                                        Console.WriteLine(m_com2.ReadAvailable());      

                           }   

             }

}

크리에이티브 커먼즈 라이선스
Creative Commons License

'General .NET' 카테고리의 다른 글

스마트클라이언트 서명키 만들기  (0) 2008/02/17
닷넷으로 다국어 지원 폼 만들기  (0) 2008/02/12
using System.IO.Ports  (0) 2008/01/17
GDI Character Set  (0) 2008/01/17
WinForm Events Flow  (0) 2008/01/09
Assembly DisplayName, Loading, Configuration File, Probing  (0) 2008/01/09
Posted by -세티-

GDI Character Set

General .NET 2008/01/17 09:53
회사에서 중국어 버전의 응용 에플리케이션을 개발 중입니다.

그런데 개발툴 윈도우즈 기본 컨트롤을 이용하여 프로그램을 작성한 후 배포하니 글자가 모두 깨지더군요.

하지만 상용컴포넌트를 이용해서 만든 컨트롤들의 글자는 모두 정상으로 나와서 이상하다 싶은 생각에

두 컨트롤의 속성을 비교해 보았습니다.

그랬더니.... GDICharSet 이라는 속성이 있었습니다.

이것이 디폴트로 129 라는 값이 있는데요. 이것을 1로 변경해 줘야 하더군요.

숫자 129는 한글 캐릭터셋을 의미한다고 하네요.

위의 문제를 해결하기 위해 자료를 검색하던 중 아래의 글을 발견해서 퍼옵니다.

Dr. GUI suggests a closer look at the System.Drawing.Font class. This class is part of the System.Drawing namespace, which provides a managed class interface that encapsulates the GDI+ APIs. You can find more details about the Font class at Font Class in the MSDN Library. Upon closer examination of this class, you'll come across a property called GdiCharSet. GdiCharSet is a byte value that specifies the character set used by a Font object, and is the answer to your question.

So, let's try out the use of GdiCharSet. For now, let's assume that you already have a reference to a Font object. In this case, all you need to do is to retrieve the value of GdiCharSet, and you're cured. Well, almost. If you look at the values for GdiCharSet for a number of fonts, all you'll get back is a number. This is because GdiCharSet is a byte value representing a particular character set. Therefore, you'll need to map this byte value to the corresponding character set, as defined in WinGDI.h. WinGDI.h is a Windows header file containing, among other things, the pre-processor directives used to define GDI constants. In order to simplify your task of mapping GdiCharSet to the corresponding character set, you can use the following table, which contains a partial list of mappings.

Value of MyFont.GdiCharSet Corresponding Character Set Defined in WinGDI.h
0 ANSI_CHARSET
1 DEFAULT_CHARSET
2 SYMBOL_CHARSET
77 MAC_CHARSET
128 SHIFTJIS_CHARSET
129 HANGUL_CHARSET
130 JOHAB_CHARSET
134 GB2312_CHARSET
136 CHINESEBIG5_CHARSET
161 GREEK_CHARSET
162 TURKISH_CHARSET
163 VIETNAMESE_CHARSET
177 HEBREW_CHARSET
178 ARABIC_CHARSET
186 BALTIC_CHARSET
204 RUSSIAN_CHARSET
222 THAI_CHARSET
238 EASTEUROPE_CHARSET
255 OEM_CHARSET


What you're looking for, vis-à-vis normal font versus symbol font, depends on whether the value of GdiCharSet is 2. As the table shows, 2 corresponds to SYMBOL_CHARSET or, in other words, the Symbol character set used by symbol fonts, like Webdings or Wingdings.

Since the table provided by Dr. GUI is not exhaustive (your WinGDI.h file might contain more pre-processor directives, depending upon the character sets that your operating system supports), you might encounter a scenario where GdiCharSet contains a value that is not listed in this table. In such a case, Dr. GUI's suggestion would be to manually look up your WinGDI.h file, which is typically located at the following path (you may need to install the Platform SDK first), for the corresponding pre-processor directive.

%Program Files%\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include
All the pre-processor directives relating to character sets are written sequentially. So, you need to start off by locating the following directive.

#define ANSI_CHARSET            0
Once you locate this directive, scan through the subsequent directives till you finally strike gold and come across an appropriate identifier defined as having the value contained in GdiCharSet. This identifier will give you details regarding the character set corresponding to GdiCharSet.

Dr. GUI now guides you through a typical scenario wherein you already have a Font object, and all you need to do is to retrieve GdiCharSet to determine whether your Font object is a normal font or a symbol font. This example should clearly explain the relationship between the character set used by your Font object, and GdiCharSet. Assume that you're working on a Windows application. Remember, any control that you use in your application will have a Font property, indicating the associated Font object.

To quickly test the relationship between the character set used by your Font object and GdiCharSet, perform the following steps:

In Visual Studio .NET, create a Windows application using either Microsoft® Visual C#® .NET or Microsoft® Visual Basic® .NET. Note that Form1 is created by default.
Drag a button onto Form1.
From the Properties window for this button, change the Name property to FontCheck.
From the Properties window for this button, change the Font property to any symbol font, like Webdings or Wingdings.
Add the following code to the FontCheck_Click event-handler.
C# code:

MessageBox.Show(FontCheck.Font.GdiCharSet.ToString());

Visual Basic .NET code:

MessageBox.Show(FontCheck.Font.GdiCharSet)

Build and run your application. Form1 is displayed.
Click the FontCheck button on Form1.
You should receive a message box with 2 as the text. Try the same example with Simplified Arabic (or another font on your system) in step 4, instead of a symbol font. You should receive a message box with 178 as the text. Finally, try this example after reverting, in step 4, to any of the normal fonts that you're used to (Arial, Microsoft Sans Serif, and the like). This time, your message box should display 0.

Dr. GUI hopes this is a vivid and watertight illustration of the concepts involved. The good doctor has also provided a sample prescription in the form of the code sample download for this article that will list all of the symbol fonts available on your computer.

So far, so good, as all this sounds simple enough. In fact, what Dr. GUI has prescribed so far should hold you in pretty good stead, as long as you try to retrieve GdiCharSet for a Font object whose GdiCharSet property has been set. However, you're bound to run into time-consuming roadblocks when you try to retrieve GdiCharSet for a Font object whose GdiCharSet property has not been set. In the previous example, Visual Studio .NET takes care of setting GdiCharSet for the Font object associated with your FontCheck button. Thus, you wouldn't notice anything unexpected. However, let's see what happens when you use the following code in the FontCheck_Click event-handler.

C# code:

Font MyFont = new Font("Wingdings",10);
MessageBox.Show(MyFont.GdiCharSet.ToString());

Visual Basic .NET code:

Dim MyFont As New Font("Wingdings", 10)
MessageBox.Show(MyFont.GdiCharSet)

When you run your application and then click the FontCheck button on Form1, you'd naturally expect a message box with 2 as the text, because Wingdings is, after all, a symbol font. However, you end up with a message box that has 1 as the text. Confused? Understandable but not incurable! Let Dr. GUI provide his diagnosis of this case...

When you create a Font object, GdiCharSet is set to the value of DEFAULT_CHARSET, unless, in the overloaded constructor, you explicitly specify the character set you wish to use. Checking the table discussed previously, DEFAULT_CHARSET maps to the value 1, which is exactly what the output text in your message box indicates. If, on the other hand, in the constructor of your Font object, you explicitly pass a parameter to specify the character set you'd like your Font object to use, GdiCharSet gets set with this value that you pass. So, if you want GdiCharSet to contain a meaningful value, the onus is on you to specify the appropriate parameter in the constructor when you create your Font object. Once you've created your Font object by specifying the character set to be used, you can obtain the character set used by retrieving the value of GdiCharSet.

However, supplying the character set in the constructor defeats the very purpose of what you're trying to achieve. Dr. GUI fully appreciates the redundancy involved here. Just the same, let's assume that you have a method that receives a Font object created by some code not under your control. In such a scenario, you have no way of knowing whether or not the GdiCharSet property for the Font object that your method receives contains a meaningful value. Without a clear understanding of Dr. GUI's diagnosis, you might be confused as to why a Font object, which has Wingdings as the Name property, returns 1 for the value of GdiCharSet, when you would clearly expect to get 2. Again, this is because the GdiCharSet property was not set when the Font was created.

With this apparent inconsistency clarified, it should be clear that GdiCharSet can solve only some of your ills. However, if the Font object in question is created without passing the character set value to the constructor, there's still the possibility of your being stumped. So, in order to empower you with some co-relation between your Font object and the character set used by the Font object, the Font class has a neat little method called ToLogFont.

In fact, the code that you've supplied to Dr. GUI is already on the right track. Use ToLogFont to populate a LOGFONT instance that is filled based on only some of the properties of your Font object. To brush up on LOGFONT, check out LOGFONT in the Online MSDN Library. Significantly, the lfCharSet field of your LOGFONT instance does not get set to DEFAULT_CHARSET. Rather, lfCharSet gets set to the value corresponding to the character set used by your Font object. Thus, even if the GdiCharSet property of your Font object contains DEFAULT_CHARSET, once you call ToLogFont, the lfCharSet field of your LOGFONT instance gets sets to 2—if the Name property of your Font object is Wingdings. You can now obtain what you desire by retrieving the value of the lfCharSet field of your populated LOGFONT instance.

But, before all that, you'll need to reference the System.Runtime.InteropServices namespace so that you'll be able to appropriately declare LOGFONT. So, go ahead and add the following statement to your code:

C# code:

using System.Runtime.InteropServices;

Visual Basic .NET code:

Imports System.Runtime.InteropServices

Dr. GUI couldn't help but notice that in your quest for a solution to your malady, you've already expertly converted the unmanaged LOGFONT structure to the best possible managed equivalent. Way to go! However, as Dr. GUI will explain presently, the good doctor advocates the use of a LOGFONT class, rather than a LOGFONT structure. This is where you've stumbled in your attempt and come up against a brick wall. So, let's go ahead and use your LOGFONT declaration, using "Class" and "class", instead of "Structure" and "struct", respectively.

C# code:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
class LOGFONT
{
  public int lfHeight;
  public int lfWidth;
  public int lfEscapement;
  public int lfOrientation;
  public int lfWeight;
  public byte lfItalic;
  public byte lfUnderline;
  public byte lfStrikeOut;
  public byte lfCharSet;
  public byte lfOutPrecision;
  public byte lfClipPrecision;
  public byte lfQuality;
  public byte lfPitchAndFamily;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
  public string lfFaceName;
}

Of course, since you're using a class rather than a structure, you'll need to explicitly instantiate your LOGFONT instance. The rest of the code advocated by Dr. GUI is in harmony with your code. So, without much further ado, let's have a look at Dr. GUI's code:

C# code:

Font MyFont = new Font("Wingdings",10);
LOGFONT MyLOGFONT = new LOGFONT();
MyFont.ToLogFont(MyLOGFONT);
// MyLOGFONT is populated.
MessageBox.Show(MyLOGFONT.lfCharSet.ToString());


Now, all that remains is to understand why you need to use a class instead of a structure.

As you've probably already noticed, ToLogFont expects you to pass an object by value. Thus, you could pass either a structure by value or a class by value and you'd still be perfectly within your rights as far as the rules relating to passing valid types. However, what you're doing is passing a System.ValueType by value, when you should be passing an object reference. Let's look at why.

The behavior you noted in your sample above (where the LOGFONT is not being filled in) is because ToLogFont receives a copy of your LOGFONT structure, which gets populated. However, these changes are not reflected in your original LOGFONT structure, which remains unpopulated. On the other hand, if you were to pass a reference to your LOGFONT instance, you would ensure that your original reference and the copy of the reference are, in fact, referring to the same LOGFONT object instance. Thus, when you declare LOGFONT as a class, the changes made to the single LOGFONT instance by ToLogFont, using a copy of your original reference, are reflected in your code.

For more details about parameter passing, check out Passing Parameters in the MSDN Library. As this piece is geared towards C# (though the concepts hold good for Visual Basic .NET too), here's something for Visual Basic .NET folks: Argument Passing Mechanism.

When you run your application, and then click the FontCheck button that is on Form1, you are rewarded for your perseverance with the result you've been waiting for all along: a message box with 2 as the text. You can try this code out for other fonts as well, and convince yourself of the veracity of this prescription. The good doctor hopes this solves the problem for you.

Thanks!
Dr. GUI wants to thank his fabulous team of specialists, including Ajay Abraham, and his dedicated nurse Maura Baughman. If Dr. GUI did surgery without y'all, the prognosis of the patients would not be good.
크리에이티브 커먼즈 라이선스
Creative Commons License

'General .NET' 카테고리의 다른 글

닷넷으로 다국어 지원 폼 만들기  (0) 2008/02/12
using System.IO.Ports  (0) 2008/01/17
GDI Character Set  (0) 2008/01/17
WinForm Events Flow  (0) 2008/01/09
Assembly DisplayName, Loading, Configuration File, Probing  (0) 2008/01/09
Base 64 디코딩 스크립트  (0) 2008/01/06
Posted by -세티-

사용자 삽입 이미지


크리에이티브 커먼즈 라이선스
Creative Commons License

'Astronomy' 카테고리의 다른 글

다만 알고자 했을 뿐이다.  (0) 2008/03/09
이야기 하나 - 칼 세이건의 코스모스에서  (2) 2008/03/09
최근 까지의 SETI 기록  (0) 2008/01/16
규표  (0) 2008/01/15
혼천의와 혼천시계  (0) 2008/01/14
3. 가대와 아이피스  (0) 2007/12/16
Posted by -세티-

규표

Astronomy 2008/01/15 19:24

사용자 삽입 이미지

시대: 조선시대 세종 19년(1437년)
설명: 규표는 규(圭)표(表)의 아주 간단한 구조로 이루어져 있다. 규(圭)에는 그림자의 길이를 알 수 있게 눈금을 새겨 놓았으며 표(表)는 그림자가 잘 비쳐지도록 되어있는 기둥이다.
이슬람에서는 규를 노몬(gnomon)이라고 부르며, 중국에서는 이미 은대에 쓰여졌다.
고대중국에서는 춘추전국시대에 8척의 규표를 이용하여 1년의 길이가 365.25일 임을 이미 알았다.

크리에이티브 커먼즈 라이선스
Creative Commons License

'Astronomy' 카테고리의 다른 글

이야기 하나 - 칼 세이건의 코스모스에서  (2) 2008/03/09
최근 까지의 SETI 기록  (0) 2008/01/16
규표  (0) 2008/01/15
혼천의와 혼천시계  (0) 2008/01/14
3. 가대와 아이피스  (0) 2007/12/16
망원경의 종류 - 굴절, 반사, 카세그레인식  (0) 2007/12/16
Posted by -세티-
TAG 규표

혼천의와 혼천시계

천원지방(天圓地方)
- 하늘은 둥글고 땅은 사각형 이라는 중국의 우주관

혼천설
- 우주를 달걀에 비유하여 하늘이 노른자위에 해당하는 땅을 둘러싸고 일주운동을 한다는 우주관

혼천의
- 혼천설을 바탕으로 일월성신의 위치를 측정하는 기구, 천체운동을 여러 개의 환으로 옮겨놓아 계절과 시각의 변화를 알아내는 필수적인 천체관측기


혼천의 구성 - 기본적으로 3개층의 환으로 구성
1. 바깥층(육합의) - 동서남북을 나타내는 삼신환, 적도환, 황도환, 백도환으로 구성
2. 맨 가운데 층(사유의) - 사유환과 망통, 직거로 구성(망통을 통해 별을 관찰)

혼천의 제작배경
- 혼천의는 중국에서 제작됨
- 하지만 삼국시대와 고려에서도 사용했다는 기록이 존재
- 정초, 정인지, 세종이 장영실을 중국에 다녀오게 한 후 세종이 이론적 설계를 하고, 장영실이 제작했다고 함.
- 17세기에 서양과학이 전파되면서 극축에 사유의 대신에 지구의를 넣기 시작함.

작동원리
- 두 개의 무거운추가 서서히 내려오는 힘을 이용하였는데 추와 연결된 축이 돌면서 혼천의 환이 돌면서
  천구의 적도와 황도를 나타내는 고리
- 2개가 따라 돌아가기 때문에 누구나 절기와 계절을 알수 있게 하였다.
  만원권에 포함된 것은 천문관측용 혼천의와는 용도가 지구가 하루에 한바퀴 도는 모습을 보여주는 일종의
  시뮬레이터이며, 천문자동표시장치이다.

사용자 삽입 이미지

[참고주소]
1. 혼천시계, 추.진자가 동력 '세계유산시계' http://news.naver.com/main/read.nhn?mode=LSD&mid=sec&sid1=105&oid=032&aid=0000209846
2. 혼천의와 혼천시계의 다른점, http://kin.naver.com/detail/detail.php?d1id=11&dir_id=110101&eid=dbDuY39Wpx13kFfFxwi8XIRoDRYjXxoO&qb=yKXDtcDH
3. 혼천의 사용방법, http://kin.naver.com/detail/detail.php?d1id=11&dir_id=110212&eid=OeCzVKW/FDGB8vtaJuQDsUlOFPLLLEv4&qb=yKXDtcDH
4. 혼천의에 관한 실학자, http://kin.naver.com/detail/detail.php?d1id=13&dir_id=1306&eid=8S3HwlEIYMlqy75LzuYTXaab4+YkLAnV&qb=yKXDtcDH

크리에이티브 커먼즈 라이선스
Creative Commons License

'Astronomy' 카테고리의 다른 글

최근 까지의 SETI 기록  (0) 2008/01/16
규표  (0) 2008/01/15
혼천의와 혼천시계  (0) 2008/01/14
3. 가대와 아이피스  (0) 2007/12/16
망원경의 종류 - 굴절, 반사, 카세그레인식  (0) 2007/12/16
망원경의 원리와 수차  (0) 2007/12/16
Posted by -세티-
작성자: 박종현
최초작성일: 2006년 12월 27일
최종작성일: 2007년 11월 15일

W3C 문서의 에러인지 어떤지는 모르겠지만 W3C 문서를 그대로 따라했다가 레이아웃이 잡히지 않아서 고생 좀 했다. W3C문서와 다른 부분은 아래에 색상으로 표시를 했다.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>A frame document with CSS 2.1</TITLE>
    <STYLE type="text/css" media="screen">
      BODY { height: 8.5in } /* Required for percentage heights below */
      #header
      {
        position: fixed;
        width: 100%;
        height: 15%;
        top: 0;
        right: 0;
        bottom: auto;
        left: 0;
        border: 1px solid;
      }
      #sidebar {
        position: fixed;
        float:left;           //추가되야 부분
        width: 10em;
        height: auto;
        top: 15%;
        right: auto;
        bottom: 100px;
        left: 0;
        border: 1px solid;
      }
      #main
      {
        position: fixed;

        width: auto;     // 삭제되야 할 부분
        height: auto;
        top: 15%;
        right: 0;
        bottom: 100px;
        left: 10em;
        border: 1px solid;
      }
      #footer {
        position: fixed;
        width: 100%;
        height: 100px;
        top: auto;
        right: 0;
        bottom: 0;
        left: 0;
        border: 1px solid;
      }
    </STYLE>
  </HEAD>
  <BODY>
    <DIV id="header">상단</DIV>
    <DIV id="sidebar">메뉴</DIV>
    <DIV id="main">메인</DIV>
    <DIV id="footer">하단</DIV>
  </BODY>
</HTML>

크리에이티브 커먼즈 라이선스
Creative Commons License

'General Web' 카테고리의 다른 글

2. xml 문서의 생성과 CSS를 이용한 XML 문서 출력  (0) 2008/04/11
xml과 10가지 설계목표  (0) 2008/04/11
[RDF 입문서] 1. 소개  (0) 2008/03/12
RDFa Basics  (0) 2008/02/22
RDF란?  (0) 2008/02/21
div를 이용한 웹 레이아웃 코드  (0) 2008/01/09
Posted by -세티-
TAG div

Dennis Lu
Doug Rothaus
Microsoft Corporation

2002년 7월

적용대상:
Microsoft ADO.NET,Microsoft .NET Framework을 사용한 경험이 있는 개발자

요약: 개발자가 Microsoft ADO.NET을 사용하여 코드를 작성할 때 고려해야 하는 표준사례와 ADO.NET 안에 포함된 개체를 사용하는 방법에 대한 지침을 소개합니다.

알림 만약, ADO.NET과 .NET Framework에 친숙하지 않다면, .NET Framework SDK에 포함되어 있는 ADO.NET을 사용한 데이터 액세스 (영문) 문서를 참조하십시오. 응용프로그램을 ADO.NET으로 마이그레이션하는 분야에 관심이 있다면, ADO 프로그래머를 위한 ADO.NET (영문) 문서를 참조하십시오.

목차

소개
.NET Framework Data Provider
DataReader, DataSet, DataAdapter, DataView 개체 사용
Command 개체 사용
Connection 개체 사용
XML과 통합
유용한 팁

소개

Microsoft ADO.NET 기반 응용프로그램을 구현할 때 최적의 성능, 확장성, 기능성을 보장하기 위하여 사용할 수 있는 표준 솔루션을 소개합니다. ADO.NET에 포함되어 있는 각 개체를 사용하는 방법에 대한 표준사례를 소개하고, ADO.NET의 설계를 최적화하기 위한 제안과 ADO.NET 기반 응용프로그램의 설계상 고려해야 하는 제안사항에 대해서 소개합니다.

본문 기사에는 다음과 같은 내용이 포함되어 있습니다.:

  • .NET Framework에 포함되어 있는 .NET Framework Data Provider에 대한 정보.
  • DataSet 개체와 DataReader개체의 차이점과 각 개체를 사용하는 표준사례.
  • DataSet 개체와 Command 개체,Connections개체를 사용하는 방법.
  • XML 통합관련 정보.
  • 일반적인 팁과 이슈사항.

ADO.NET 표준사례에 대한 좀 더 자세한 정보는 MSDN 라이브러리에 소개된 .NET 데이터 액세스 아키텍처 가이드 (영문) 를 참조하십시오. .NET 데이터 액세스 아키텍처 가이드에서는 주로 Microsoft SQL Server 7.0 이후 버전의 기술구조를 중점으로 소개합니다.

다음은 ADO.NET에 대한 추가적인 정보를 제공하는 기사 목록입니다.

.NET Framework Data Provider

.NET Framework Data Provider는 데이터 원본과 응용프로그램을 연결시켜 주는 교량역할을 합니다. .NET Framework Data Provider는 데이터 원본으로부터 질의 결과를 반환하여 주며, 데이터 원본에 대한 명령을 실행하고, DataSet 개체에서 발생한 변경내역을 데이터 원본에 반영하는 역할을 담당합니다. 본문에서는 각 상황에 가장 적합한 .NET Framework를 선택하기 위해 고려해야 하는 팁을 소개합니다.

어떤 .NET Framework Data Provider를 사용해야 할까요?

응용프로그램이 최상의 성능을 발휘할 수 있도록 하기 위해서는, 각 데이터 원본에 최적화되어 있는 .NET Framework Data Provider를 사용해야 합니다. 응용프로그램에서 사용할 수 있는 데이터 공급자는 여러 종류가 있습니다. 다음 표는 각 데이터 원본에 최적화되어 있는 데이터 공급자에 대해 설명하고 있습니다.

Data Provider 상세설명
SQL Server .NET Data Provider System.Data.SqlClient 네임스페이스를 사용합니다.

Microsoft SQL Server 7.0 또는 그 이후 버전을 사용하는 미들티어 응용프로그램에서 사용할 것을 권장합니다.

Microsoft 데이터엔진(MSDE)이나 Microsoft SQL Server 7.0 또는 그 이후 버전을 기반으로 한 단일계층 응용프로그램에서 사용할 것을 권장합니다.

Microsoft SQL Server 6.5 버전이전을 사용하는 경우에는 OLE DB .NET Data Provider 에 포함되어 있는 OLE DB Provider for SQL Server (영문)를 사용해야 합니다.

OLE DB .NET Data Provider System.Data.OleDb 네임스페이스를 사용합니다.

Microsoft SQL Server 6.5 버전이전이나 .NET Framework SDK의 OLE DB .NET Data Provider에 의해 사용되는 OLE DB 인터페이스 (영문) 목록에 포함된 OLE DB 인터페이스를 지원하는 OLE DB 공급자를 사용하는 미들티어 응용프로그램에서 사용할 것을 권장합니다. (OLE DB 2.5 인터페이스는 필수가 아닙니다.)

Microsoft SQL Server 7.0 이후 버전에서는, SQL Server .NET Data Provider를 사용할 것을 권장합니다.

Microsoft Access 데이터베이스를 사용하는 단일 계층 응용프로그램인 경우, OLE DB .NET Data Provider를 사용할 것을 권장합니다. 미들티어 응용프로그램에서는 Access 데이터베이스를 사용하지 않을 것을 권장합니다.

OLE DB Provider for ODBC (MSDASQL)에 대한 지원은 비활성화되었습니다. ODBC 데이터원본에 접근하는 경우에 사용할 수 있는 ODBC .NET Data Provider(다운로드 (영문))도 현재 다운로드 받을 수 있으며, .NET Framework 1.1버전에 포함되게 될 것입니다.

ODBC .NET Data Provider ODBC .NET Data Provider 는 현재 다운로드 가능합니다.(다운로드 (영문))

Microsoft.Data.Odbc 네임스페이스를 사용합니다.

ODBC 드라이버를 사용하여 데이터 원본에 접근할 수 있도록 하는 기능을 제공합니다.

알림 ODBC .NET Data Provider 는 .NET Framework의 1.1버전에 포함될 예정입니다. ODBC .NET Data Provider 는 System.Data.Odbc 네임스페이스를 사용합니다.

.NET Data Provider for Oracle .NET Data Provider for Oracle 은 현재 다운로드 가능합니다.(다운로드 (영문))

System.Data.OracleClient 네임스페이스를 사용합니다.

Oracle 데이터 원본(8.1.7 이후 버전)에 접근할 수 있도록 하는 기능을 제공합니다.

알림 .NET Data Provider for Oracle 은 .NET Framework의 1.1버전에 포함될 예정입니다.

사용자정의 .NET Data Provider ADO.NET 은 필요에 따라 직접 .NET Framework Data Provider를 구현할 수 있도록, 필요한 최소한의 인터페이스를 제공합니다. 사용자정의 Data Provider를 생성하기 위한 자세한 정보는 .NET Framework SDK에 포함되어 있는 .NET Framework Data Provider 구현 (영문) 문서를 참조하십시오.
SQLXML관리 클래스 XML for Microsoft SQL Server 2000 (SQLXML 3.0)에는 Microsoft SQL Server 2000 이후 버전의 XML 지원기능에 접근할 수 있도록 하기 위한 SQLXML 관리 클래스가 포함되어 있습니다. 예를 들어, SQLXML 관리 클래스를 사용하면 XML 템플릿을 실행하거나, XPath 질의를 사용하여 서버 데이터를 질의할 수 있으며, Updategram이나 Diffgram을 사용하여 데이터를 변경할 수 있습니다.

SQLXML 1.0이나 SQLXML 2.0의 기능에 추가하여, SQLXML3.0에서는 SQL Server 2000에 대한 웹 서비스 기능을 제공합니다. SQLXML 3.0을 사용하면, 저장프로시저나 XML 템플릿을 SOAP 프로토콜을 사용하여 웹 서비스로 생성할 수 있습니다.

SQLXML 3.0 은 현재 다운로드 가능합니다.(다운로드 (영문))

SQL Server 7.0 이후 버전에 연결하기

Microsoft SQL Server 7.0 및 이후 버전에 연결할 때 최적의 성능을 발휘하도록 하기 위해서는 SQL Server .NET Data Provider를 사용해야 합니다. SQL Server .NET Data Provider는 다른 기술 계층 없이 곧바로 SQL Server에 접근할 수 있도록 설계되었습니다. 그림 1에는 SQL Server 7.0 및 이후 버전에 연결할 때 사용할 수 있는 다양한 기술을 비교한 도표가 나타나 있습니다.

그림 1. SQL Server 7.0 이후 버전에 접근하기 위한 연결방법

ODBC 데이터원본 연결

ODBC .NET Data Provider는 Microsoft.Data.Odbc ODBC .NET Data Provider는 Microsoft.Data.Odbc 네임스페이스를 사용하며, .NET data providers for SQL Server 나 OLE DB와 동일한 기술구조를 가지고 있습니다. ODBC .NET Data Provider (다운로드 (영문))는 "ODBC" 접두사를 명명규칙(예를 들어, OdbcConnection)으로 하고, 표준 ODBC 연결문자열을 사용합니다.

알림 ODBC .NET Data Provider 는 .NET Framework 1.1 버전에 포함될 예정입니다. ODBC .NET Data Provider 는 System.Data.Odbc 네임스페이스를 사용합니다.

DataReader, DataSet, DataAdapter, DataView 사용

ADO.NET은 관계형 데이터를 조회하고 메모리상에 저장하기 위해 DataSet 개체와 DataReader개체를 제공합니다.DataSet개체는 메모리 상에서 테이블간의 관계뿐만 아니라 데이터에 대한 제약조건, 정렬을 지원하는 완전한 관계형 데이터 저장소 기능을 제공합니다. DataReader 개체는 데이터베이스로부터 데이터를 빠르고, 앞으로만 이동가능한, 읽기전용 데이터 스트림으로 조회하는 기능을 제공합니다.

DataSet 체를 사용할 때는, 데이터 원본과 상호작용하기 위해 주로 DataAdapter 개체(CommandBuilder 개체 포함)를 사용합니다. 또한, DataSet 개체내부에서 데이터를 정렬하거나 필터링하기 위해서 DataView 개체를 사용합니다. DataSet 개체는 강력하게 형식화된(strongly typed) DataSet을 생성하기 위해 상속될 수 있으며, 강력하게 형식화된 DataSet 에는 테이블, 행, 열 등이 강력하게 형식화된 개체 속성으로 표현됩니다.

이번 기사에서는 언제 DataSet 개체와 DataReader 개체를 사용해야 하는지에 대한 정보와 DataSet 개체와 DataReader 개체에 포함되어 있는 데이터에 대한 접근방법을 최적화하는 방법, DataAdapter(CommandBuilder 개체 포함) 개체와 DataView개체를 최적화하여 사용하는 방법에 대한 팁을 제공합니다.

DataSet 개체 vs. DataReader 개체

응용프로그램을 설계할 때 DataSet 개체를 사용할 것인지, DataReader 개체를 사용할 것인지를 결정하기 위해서는, 반드시 응용프로그램에서 요구하는 기능을 검토해야 합니다.

다음과 같은 응용프로그램 요구사항이 있는 경우에는, DataSet 개체를 사용해야 합니다.

  • 여러 개의 결과 테이블간의 검색이 필요한 경우
  • 여러 개의 데이터 원본으로부터 데이터를 조작해야 하는 경우 (예를 들어, 하나 이상의 데이터베이스로부터 데이터를 조회해야 하거나, XML 파일, 스프레드 시트에서 데이터를 통합하여 조작해야 하는 경우)
  • XML Web Service나 응용프로그램 계층간에 데이터를 교환해야 하는 경우 DataReader 개체와는 달리, DataSet 개체는 원격 클라이언트로 전달이 가능합니다.
  • 데이터에 대한 정렬, 검색, 필터링 작업의 성능향상을 위해, 행 집합을 캐싱한 다음, 재사용해야 하는 경우
  • 대량의 행 단위 처리가 필요한 경우. DataReader 개체를 사용하여 각 행 단위로 결과집합을 반환하게 되면, DataReader 개체에서 필요이상으로 연결을 유지해야 하기 때문에, 성능상에 문제가 될 수 있습니다.
  • XSLT 변환이나 XPath 질의와 같은 XML 작업을 사용하여 데이터를 조작해야 하는 경우

다음과 같은 응용프로그램 요구사항이 있는 경우에는, DataReader 개체를 사용해야 합니다.

  • 데이터를 캐시에 저장할 필요가 없는 경우
  • 결과집합이 너무 커서 메모리상에 저장할 수 없는 경우
  • 데이터에 앞으로만 이동가능하고, 읽기전용인 상태로 빠르게 접근해야 하는 경우
알림 DataAdapter 개체는 DataSet 개체에 데이터를 입력하기 위해 DataReader 개체를 사용합니다. 그러므로, DataSet 개체 대신에 DataReader 개체를 사용하게 되면, 성능상으로 DataSet 개체에서 사용하는 메모리 공간을 절약할 수 있으며, DataSet 개체에 데이터를 입력하는 과정에서 소요되는 자원을 절약할 수 있습니다. 응용프로그램에 요구사항에 따라 반드시 사용해야 하는 경우에만 DataSet 개체를 사용하고, 그 외의 경우, DataReader 개체를 사용하게 되면, 그만큼 성능상에 효과를 얻을 수 있습니다.

강력하게 형식화된 DataSet 개체를 사용하는 효과

DataSet 개체를 사용함으로써 얻을 수 있는 효과 중 하나는 DataSet 개체를 상속하여 강력하게 형식화된 DataSet 개체를 생성할 수 있다는 것입니다. 강력하게 형식화된 DataSet 개체를 사용하면, 설계 시점의 데이터형 점검기능과 Microsoft Visual Studio .NET 의 문장 자동완성 기능을 활용할 수 있습니다. DataSet 개체를 고정된 스키마 또는 관계형 구조로 사용하는 경우, 컬렉션 개체의 항목이 아니라, 행과 열 속성을 제공하는 강력하게 형식화된 DataSet 개체를 생성할 수 있습니다. 예를 들어,Customer 테이블에 포함된 특정 행의 Name 열에 접근하는 대신, Customer 개체의 Name 속성으로 접근할 수 있습니다. 형식화된 DataSet 개체는 DataSet 클래스에서 파생되었기 때문에, DataSet 클래스의 기능을 모두 사용할 수 있습니다. 즉, 형식화된 DataSet 개체는 원격에서 접근이 가능하며, DataGrid와 같은 데이터 바인딩 컨트롤의 데이터 원본으로 사용할 수 있습니다. 스키마가 형식화되어 있지 않은 경우에도, 순수 DataSet 개체의 기능을 모두 사용할 수 있지만, 강력하게 형식화된 DataSet 개체에서 제공해 주는 추가기능은 사용할 수 없습니다.

강력하게 형식화된 DataSet 내에서 Null값 처리

강력하게 형식화된 DataSet을 사용하면, null 값을 처리하기 위해 XML 스키마 정의 언어(XSD) 구문을 사용할 수 있습니다. nullValue 주석(annotation)을 사용하여 DBNull을 특정한 값이나 String.Empty으로 변환할 수도 있고, null값에 대한 참조로 유지하거나 예외를 발생시킬 수도 있습니다. 어떤 옵션을 선택할 것인지는 응용프로그램 컨텍스트에 따라 결정됩니다. 기본값으로는, null 값에 대한 참조가 발생하게 되면, 예외를 발생시키게 됩니다.

좀 더 자세한 정보는, 형식화된 DataSet사용 (영문) 기사를 참조하십시오.

DataSet 개체내의 데이터 갱신

서버로부터 변경된 값을 DataSet 개체에 반영하기 위해서는, DataAdapter.Fill 메서드를 사용합니다. DataTable 개체에 기본 키가 설정된 경우, DataAdapter.Fill 메서드는 해당 기본 키를 기준으로 변경된 행을 매핑하고, 기존 행에 변경된 서버 값을 적용시키게 됩니다. 새로운 데이터로 갱신된 행의 RowState 속성은 데이터 갱신작업이전에 변경된 행이라고 할지라도, Unchanged로 설정됩니다. DataTable 개체에 기본 키가 설정되어 있지 않은 경우에는, DataAdapter.Fill 메서드는 잠재적으로 중복된 기본 키 값을 사용하여 새로운 행을 추가합니다.

현재 테이블 내에 존재하는 행의 변경된 값을 유지한 상태로, 해당 테이블의 데이터를 갱신하고자 한다면, DataAdapter.Fill 메서드를 사용하여 새로운 DataTable 개체에 데이터를 입력한 다음, Merge 메서드의 perserveChanges 인수를 true로 설정한 상태에서, 해당 DataTable 개체를 DataSet 개체에 병합하면 됩니다.

DataSet 개체 내에서 데이터 검색

DataSet 개체에서 특정한 검색조건에 일치하는 행을 조회하고자 질의하는 경우, 인덱스 기반 검색을 사용하면, 검색 성능을 개선할 수 있습니다. DataTable 개체의 PrimaryKey 속성값을 설정하게 되면, 인덱스를 생성할 수 있습니다. DataTable 개체에 대해서 DataView를 생성하는 경우에도, 인덱스가 생성됩니다. 인덱스 기반 검색을 사용할 수 있는 몇 가지 팁이 아래에 소개되어 있습니다.

  • DataTable 개체의 PrimaryKey 속성으로 지정된 열에 대한 질의를 수행하는 경우, DataTable.Select 메서드 대신 DataTable.Rows.Find 메서드를 사용합니다.
  • 기본 키 열이 아닌 열에 대한 질의를 수행하는 경우, DataView 개체를 사용하면 데이터에 대한 다양한 질의의 성능을 향상시킬 수 있습니다. DataView를 정렬하게 되면, 검색을 할 때 사용할 수 있는 인덱스가 생성됩니다. 기존 DataTable 개체에 대해 질의를 수행하기 위해 사용하는, Find 메서드와 FindRows 메서드를 DataView 개체도 동일하게 제공합니다.
  • 테이블을 정렬할 필요가 없는 경우라도, DataTable 개체에 대해 DataView를 생성하게 되면, 인덱스 기반 검색의 장점을 활용할 수 있습니다. 데이터에 대해 다수의 질의를 수행하는 경우에는, 인덱스 기반 검색의 장점을 활용할 수 있습니다. 만약, 단일 질의만 수행해야 하는 경우라면, 오히려 인덱스를 생성하기 위해 필요한 처리과정이 인덱스를 사용함으로써 얻을 수 있는 성능상의 장점을 상쇄시키게 됩니다.

DataView 구성

DataView가 생성되거나, Sort, RowFilter, RowStateFilter 속성이 수정된 경우에는, 기존 DataTable의 데이터에 대한 인덱스를 생성합니다. DataView 개체를 생성하는 경우, 기존 DataTable에 설정된 Sort, RowFilter, RowStateFilter 값을 생성자 인수로 전달받게 됩니다. 그러므로, 설정된 각 속성값에 따라 한번에 인덱스가 생성될 수 있습니다. 비어있는 DataView를 생성하거나, Sort, RowFilter, RowStateFilter 속성을 사후에 설정하게 되면 적어도 두 번 이상 인덱스 생성 작업이 수행됩니다.

페이징

ADO.NET은 데이터 원본으로부터 어떤 데이터를 가져올 것인지를 명시적으로 통제할 수 있으며, DataSet 개체 내에 캐시할 데이터의 양을 지정할 수 있는 기능을 제공합니다. 질의의 결과에 대한 페이징을 처리하기 위한 명시적인 해답은 없지만, 응용프로그램의 설계단계에서 페이징을 처리하기 위해 고려할 수 있는 몇 가지 팁을 소개합니다.

  • startRecord 인수와, maxRecord 인수를 입력받는, 오버로드된 DataAdapter.Fill 메서드를 사용하지 않아야 합니다. 해당 오버로드된 DataAdapter.Fill 메서드를 사용하게 되면, DataSet에는 startRecord 인수로 지정된 레코드로부터 시작하여 maxRecords 인수로 지정된 레코드의 수만큼 데이터를 입력하게 되지만, 불필요한 전체 질의 결과가 모두 반환되게 됩니다. 결국, 요청되지 않는 레코드를 읽기 위해 불필요한 처리과정이 필요하게 되며, 추가적인 레코드를 반환하기 위해 서버 자원이 필요이상으로 사용됩니다.
  • 한 번에 한 페이지에 필요한 데이터만 가져오기 위해서, TOP 지시자와 함께 WHERE 절과 ORDER BY 절을 조합하여 SQL 문장을 생성하게 됩니다. 이러한 기술을 사용하기 위해서는 우선 각 행에 대한 식별자가 존재하느냐가 매우 중요한 요소가 됩니다. 다음 페이지를 위한 레코드를 검색하기 위해, WHERE 절을 현재 페이지의 맨 마지막 레코드보다 큰 레코드만을 조회할 수 있도록 수정해야 합니다. 각 질의를 수행할 때는 TOP 구문을 사용하여 다음 페이지에 필요한 레코드만을 가져오게 됩니다. 이전 페이지를 조회하기 위해서는, 결과집합을 역순으로 정렬하여 데이터를 반환해야 합니다. 역순으로 정렬한 결과의 TOP을 반환하는 방법을 사용하면, 질의의 맨 마지막 페이지를 반환할 수 있으며, 필요한 경우, 역순으로 정렬된 데이터를 표시하기 전에 다시 정렬을 해서 표시되도록 해야 합니다. 좀 더 자세한 정보는 질의 결과를 통한 페이징 구현 (영문) 기사를 참조하십시오.
  • 또 다른 방법으로 한 페이지에 해당하는 레코드만을 반환하기 위해 하위 SELECT 구문과 TOP 지시자를 조합하여 SQL 문장을 만드는 방법을 사용할 수 있습니다. 하위 SELECT 구문과 TOP 지시자를 조합하여 사용하는 방법은 각 행을 식별하기 위한 식별자가 없는 경우에도 사용할 수 있습니다. 먼저 필요로 하는 페이지 수에 페이지 당 행수를 곱하여 반환해야 하는 레코드 수를 계산해야 합니다. 그 다음, 앞 단계에 계산한 레코드 수를 TOP 지시자로 지정한 SQL 질의를 오름차순으로 정렬된 순서로 생성합니다. 다음 단계로, 앞에서 작성한 질의를 하위 질의로 포함하는 SELECT 질의를 하나 더 생성하여, 한 페이지에 필요한 레코드만 반환할 수 있도록 TOP 지시자를 사용하며, 외부 SELECT 질의의 경우는 역순으로 정렬하여 반환될 수 있도록 합니다. 결과적으로, 하위 SELECT 질의에서 반환하는 맨 마지막 페이지를 반환합니다. 예를 들어, 페이지 당 레코드 수가 10 건이고, 세 번째 페이지를 반환하기 위해서는, 다음과 같은 질의를 사용하면 됩니다. SELECT TOP 10 * FROM (SELECT TOP 30 * FROM Customers ORDER BY Id ASC) AS Table1 ORDER BY Id DESC

    질의의 결과가 역순으로 정렬된 상태로 반환된다는 것에 유념할 필요가 있습니다. 필요하다면, 다시 오름차순으로 정렬될 수 있도록 다시 정렬을 해야 합니다.

  • 데이터가 자주 변경되지 않는다면, DataSet 개체내에 로컬로 레코드를 캐시하면 성능을 향상시킬 수 있습니다. 예를 들어, 사용자가 첫 번째 페이지부터 마지막 페이지까지 모두 캐시된 데이터에서 검색할 수 있도록, 필요한 경우, 데이터 원본에 대한 한 번의 질의를 통해, 로컬 DataSet 개체 내에 10 개의 페이지를 저장할 수도 있습니다. 좀 더 자세한 정보는 .NET 데이터 액세스 아키텍쳐 가이드 (영문) 기사를 참조하십시오.

    스키마가 적용된 DataSet 개체에 데이터 채우기

    DataAdapter.Fill 메서드를 사용하여, DataSet 개체의 설정된 스키마를 기준으로 SelectCommand 명령의 수행결과로 반환된 데이터를 DataSet 개체내에 입력합니다. 데이터 채우기의 대상이 되는 테이블 명칭이 지정되지 않으면, Fill 메서드가 새로운 테이블을 생성하게 됩니다. 기본값으로, Fill 메서드는 열과 열의 데이터형만을 지정하게 됩니다.

    DataAdapter 개체의 MissingSchemaAction 속성을 설정하면, Fill 메서드의 기본 동작을 재정의(override)할 수 있습니다. 예를 들어, 기본 키 정보, unique 제약조건, null 허용여부, 열의 최대 길이, 읽기전용 열, 자동증가 열과 같은 열 속성이 포함된 테이블 스키마를 생성하도록 하기 위해서, DataAdapter.MissingSchemaAction 속성값을 MissingSchemaAction.AddWithKey로 지정할 수 있습니다. 또한, DataAdapter.Fill 메서드를 호출하기 전에 DataAdapter.FillSchema 메서드를 호출하여, DataSet에 데이터를 채우기 작업을 수행하기 전에 제대로 구성된 스키마에 데이터가 매핑될 수 있도록 보증해 줄 수 있습니다.

    FillSchema 메서드를 호출하게 되면, 추가적인 스키마 정보를 조회하기 위해서 서버로 별도의 라운드트립이 발생하게 됩니다. 최대한 성능을 보장해 주기 위해서는, DataSet에 스키마를 정의하거나, Fill 메서드를 호출하기 전에 DataAdapter개체의 MissingSchemaAction 속성을 설정해 주는 것이 바람직합니다.

    CommandBuilder 개체 사용 표준사례

    CommandBuilder 개체는, 단일 테이블에 대한 SELECT 기능을 수행하는, DataAdapter 개체의 SelectCommand 속성을 기반으로 하여, 자동으로 InsertCommand, UpdateCommand, DeleteCommand 속성을 생성해 줍니다. CommandBuilder 개체가 최적의 성능을 발휘할 수 있도록 하기 위한 몇 가지 팁을 소개합니다.

    • CommandBuilder 개체는 디자인 시점이나 임의 시나리오를 위해서만 제한적으로 사용해야 합니다. DataAdapter 개체에 각 Command 속성을 생성하기 위한 처리작업은 성능에 악영향을 미칠 가능성이 있습니다. 사전에 사용할 INSERT/UPDATE/DELETE 문장을 알고 있는 경우라면, 명시적으로 설정하는 것이 바람직합니다. 올바른 설계방법은 INSERT/UPDATE/DELETE 작업을 수행하는 저장 프로시저를 생성한 다음, 각 저장 프로시저를 DataAdapter 개체의 각 Command 속성에 명시적으로 지정하는 것입니다.
    • CommandBuilder 개체는 다른 Command 속성값을 지정하기 위해서 DataAdapter의 SelectCommand 속성을 사용합니다. DataAdapter 개체의 SelectCommand 속성을 변경하고자 하는 경우에는, 모든 관련 속성에 변경내역을 반영하기 위해 RefreshSchema 메서드를 호출해야 합니다.
    • DataAdapter 개체의 Command 속성이 null값(Command 속성은 Null값이 기본값으로 설정)으로 설정되어 있는 경우에는, CommandBuilder 개체가 각 Command 속성을 생성하게 됩니다. Command 속성이 명시적으로 지정되게 되면, CommandBuilder 개체는 그 값을 덮어쓰지 않습니다. CommandBuilder 개체가 이미 값이 지정된 Command 속성에 명령을 생성하도록 하기 위해서는, 먼저 해당 Command 속성을 Null로 설정해 주어야 합니다.

    SQL 배치 문장 처리

    대부분의 데이터베이스에서는 여러 개의 명령을 조합하여 하나의 배치작업으로 실행하는 기능을 제공합니다. 예를 들어, SQL 서버에서는 세미콜론(;)을 사용하여 명령을 구분할 수 있습니다. 여러 개의 명령을 하나의 배치작업으로 조합하여 실행하게 되면, 서버로의 라운드트립을 줄여 줄 수 있기 때문에, 응용프로그램의 성능을 향상시킬 수 있습니다. 예를 들어, 응용프로그램에서 발생하는 삭제요청을 하나로 조합한 다음, 한꺼번에 데이터원본에 해당 행을 삭제하도록 배치작업을 실행할 수 있습니다.

    여러 개의 명령을 하나의 배치로 실행하는 방법을 사용하면, 성능을 향상시킬 수 있지만, DataSet 개체에서 데이터에 대한 변경내역을 관리할 때, 응용프로그램의 복잡성이 증가하게 됩니다. 응용프로그램의 단순성을 유지하기 위해서는, DataSet 내부에 포함된 DataTable별로 DataAdapter 개체를 생성할 수 있습니다.

    DataSet 개체에 여러 개의 테이블 데이터 채우기

    여러 개의 테이블을 조회하는 SQL 배치 문장을 사용하는 경우, Fill 메서드에서 테이블 명칭을 지정하게 되면, 첫 번째 결과집합에 대해서는 지정한 테이블 명칭이 부여하게 됩니다. 그 다음, 나머지 결과집합을 저장하기 위한 테이블은, Fill 메서드에서 지정된 테이블 명칭 뒤에 숫자를 하나씩 증가시켜 가면서 명칭을 부여하게 됩니다. 예를 들어, 다음과 같은 코드를 실행해 볼 수 있습니다.

    'Visual Basic Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection) Dim ds As DataSet = New DataSet() da.Fill(ds, "Customers") //C# SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection); DataSet ds = new DataSet(); da.Fill(ds, "Customers");

    Customers 테이블에서 조회한 결과는 "Customers" 테이블에 입력됩니다. 그 다음, Orders 테이블에서 조회한 결과는 "Customers1"이라는 명칭이 부여된 DataTable 개체로 입력됩니다.

    DataSet 개체에 데이터가 채워진 다음, 해당 DataTable 개체의 TableName 속성을 "Customers1"에서 "Orders"로 쉽게 변경할 수 있습니다. 하지만, "Customers" 테이블에 대해 데이터 채우기 작업을 다시 수행하게 되면, 수정된 "Orders" 테이블은 무시되고, 또 다른 "Customers1" 테이블이 다시 생성됩니다. 이러한 문제점을 해결하기 위해서는, "Customers1" 테이블을 "Orders" 테이블로 매핑하기 위해서 DataTableMapping 개체를 생성해야 합니다. 예를 들면, 아래의 코드와 같이 DataTableMapping 개체를 생성할 수 있습니다.

    'Visual Basic Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection) da.TableMappings.Add("Customers1", "Orders") Dim ds As DataSet = New DataSet() da.Fill(ds, "Customers") //C# SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection); da.TableMappings.Add("Customers1", "Orders"); DataSet ds = new DataSet(); da.Fill(ds, "Customers");

    DataReader 개체 사용

    일반적인 DataReader 개체의 사용에 관련된 질문사항에 대한 답변과 최적의 성능을 보장하기 위한 몇 가지 팁을 소개합니다.

    • DataReader 는 연결된 Command 속성에 설정된 출력파라미터에 접근하기 전에 반드시 종료(close)되어야 합니다.
    • 데이터에 대한 읽기 작업이 종료되는 시점에 DataReader 개체는 항상 종료되어야 합니다. Connection 개체가 DataReader 개체에서 반환하는 데이터만을 위해 사용된다면, DataReader 개체를 종료한 다음, 해당 Connection 개체도 바로 종료해야 합니다. Connection 개체를 명시적으로 종료하는 방법의 대안으로는, ExecuteReader 메서드에 CommandBehavior.CloseConnection 인수 값을 전달하여, DataReader 개체가 종료되는 시점에서 관련된 Connection 개체를 종료할 수 있도록 설정할 수 있습니다. 이러한 방법은 ExecuteReader 메서드로부터 DataReader 개체가 반환된 다음, DataReader 개체나 관련된 Connection 개체를 종료시키기 위한 별도 절차가 필요하지 않기 때문에, 특히 유용하게 사용됩니다.
    • DataReader 개체는 응용프로그램 계층간에 원격으로 사용될 수 없습니다. DataReader 개체는 반드시 연결된 데이터 액세스 모델로 설계되어야 합니다.
    • 열의 데이터에 접근할 때, GetString, GetInt32 등과 같은 형식화된 접근자(accessor)를 사용할 수 있습니다. 이러한 형식화된 접근자를 사용하게 되면, GetValue 메서드로부터 반환된 개체를 특정한 데이터형으로 형변환하기 위한 추가적인 처리절차가 필요하지 않습니다.
    • 하나의 Connection개체를 사용하여, 한 번에 하나의 DataReader 개체만 열 수 있습니다. ADO에서는 하나의 Connection 개체를 연 다음, 전진지향, 읽기 전용 커서를 사용하여, 두 개의 레코드집합을 요청하는 경우, 암시적으로 제 2의 풀링되지 않은 연결을 생성하여, 커서를 관리하기 위한 정보를 저장하고, 처리가 완료되면 암시적으로 종료시킵니다. ADO.NET에서는 예전에 사용하여왔던 관행에서 벗어나야만 합니다. 동일한 데이터 저장소를 대상으로, 동시에 두 개의 DataReader 개체를 열어야 한다면, 명시적으로 두 개의 Connection 개체를 연 다음, 각 연결을 사용하여 DataReader 개체를 하나씩 열어야 합니다. 이러한 방법을 사용하여, ADO.NET에서는 풀링된 연결에 대한 사용을 통제할 수 있습니다.
    • 기본값으로, DataReader 개체는 읽기작업의 대상이 되는 전체 행 정보를 메모리로 업로드합니다. 그렇기 때문에, 현재 행의 각 열에 대해서는 임의 접근이 가능합니다. 만약, 열에 대한 임의 접근이 필요없는 경우라면, 성능향상을 위해 ExecuteReader 메서드를 호출할 때, CommandBehavior.SequentialAccess 속성을 지정하여 전달할 수 있습니다. CommandBehavior.SequentialAccess 속성이 지정되면, DataReader 개체의 기본동작방법이 변경되어 요청이 발생한 데이터만 메모리로 업로드하게 됩니다. CommandBehavior.SequentialAccess 속성이 지정되면, 반환되는 각 열의 순서에 따라 데이터에 접근하게 됩니다. 즉, 한 번 순서에 따라 반환된 열에 대한 읽기 작업을 수행하고 나면, 다시 그 값을 읽을 수는 없게 됩니다.
    • DataReader 개체로부터 데이터 읽기작업을 완료한 다음에도, DataReader 개체 내부에 읽지 않은 데이터가 계속 존재하는 경우라면, Close 메서드를 호출하기 전에 Command 개체의 Cancel 메서드를 호출해야 합니다. 먼저, DataReader 개체의 Close 메서드를 호출되면, DataReader 내에 읽지 않은 상태로 대기 중인 결과값을 조회하는 원인이 되고, 커서를 종료하는 작업에 앞서, 이러한 스트림 조회작업을 종료하는 추가작업이 발생하게 되는 원인이 됩니다. 먼저, Command 개체의 Cancel 메서드를 호출하게 되면, DataReader개체의 Close 메서드를 호출할 때, DataReader 내부에 존재하는 읽지 않은 데이터에 대한 조회작업을 수행하지 않도록 하기 위해, 서버상에 존재하는 결과값을 모두 폐기하게 됩니다. 만약, Command 개체가 출력 파라미터를 반환하는 경우, Cancel 메서드를 호출하게 되면 출력파라미터에 할당된 값도 모두 폐기됩니다. 그러므로, 출력 파라미터를 읽어야 하는 경우라면, Command 개체의 Cancel 메서드를 호출하지 말고, DataReader 개체의 Close 메서드만 호출해야 합니다.

    BLOB 데이터 처리

    DataReader 개체를 사용하여 BLOB 데이터를 조회하는 경우, ExecuteReader 메서드를 호출할 때, CommandBehavior.SequentialAccess 속성을 설정해야 합니다. DataReader 개체는 기본적으로 모든 읽기 작업의 대상이 되는 전체 행을 메모리로 업로드하게 되며, BLOB 데이터의 경우, 매우 대용량일 수도 있기 때문에, 단일 BLOB 데이터가 메모리의 상당한 부분을 소모해 버릴 수도 있습니다. SequentialAccess 속성이 설정되게 되면, DataReader 개체는 요청된 데이터만을 메모리에 업로드합니다. 그 다음, GetBytes 메서드나 GetChars 메서드를 사용하여, 한 번에 메모리로 업로드하는 데이터의 양을 통제할 수 있습니다.

    SequentialAccess 속성을 지정하게 되면, DataReader에 지정된 순서를 벗어나서 다른 필드에 접근할 수 없다는 사실을 기억해 두어야 합니다. 즉, 질의결과에 3 개의 열이 포함되어 있고, 첫 번째, 두 번째 열은 일반 데이터이고, 세 번째 열이 BLOB 데이터인 경우, 순서대로 첫 번째 열 값을 읽은 다음, BLOB 열 데이터 값을 읽기 전에 두 번째 열 값을 반드시 읽어야 합니다. 데이터가 순서대로 반환되기 때문에, 한 번 DataReader 개체를 통해 읽기 작업이 수행된 열에 대해서는 다시 읽기 작업을 수행할 수 없게 됩니다.

    ADO.NET을 사용하여 BLOB 데이터를 처리하는 작업에 대한 자세한 내용은 데이터베이스에서 BLOB 데이터 가져오기 (영문) 기사를 참조하십시오.

    Commands 개체 사용

    ADO.NET 에서는 명령을 실행하기 위한 메서드를 제공할 뿐만 아니라, 실행되는 명령을 최적화하기 위한 옵션도 제공합니다. 다음에서는 명령을 실행하는 표준 방법과 실행된 명령의 성능을 최적화하기 위한 몇 가지 팁을 소개합니다.

    OleDbCommand 표준사례

    여러 .NET Framework data provider 간에 명령을 실행하는 방법을 가능한 한 표준화해서 사용해야 합니다. 하지만, 각 데이터 공급자간에 차이점이 존재합니다. 다음에서는 .NET Framework Data Provider for OLE DB를 사용하여 명령을 실행할 때, 최적의 성능을 보장하기 위한 몇 가지 팁을 소개합니다.

    • 저장프로시저를 호출하기 위해서는 ODBC CALL 구문과 함께 CommandType.Text 속성을 사용합니다. CommandType.StoredProcedure 속성을 지정하면, 암시적으로 ODBC CALL 구문을 생성하게 됩니다.
    • 반드시 OleDbParameter 개체의 데이터형, 크기, 정확도 및 배율(numeric,decimal 데이터형인 경우) 등을 지정해야 합니다. 파라미터에 대한 정보를 명시적으로 설정하지 않으면, OleDbCommand 개체에서 명령이 실행될 때마다, 해당 OLE DB 파라미터 접근자(accessor)를 다시 생성하게 됩니다.

    SqlCommand 표준사례

    SqlCommand 개체를 사용하여 저장 프로시저를 실행하는 경우에 적용할 수 있는 몇 가지 팁을 소개합니다. 저장 프로시저를 호출한다면, SqlCommand 개체의 CommandType 속성을 StoredProcedure으로 지정해야 합니다. CommandType 속성을 StoredProcedure으로 지정하면, 실행하는 명령이 명시적으로 저장 프로시저라는 것을 알 수 있기 때문에, 명령을 실행하기 전에 파싱하는 절차가 생략됩니다.

    Prepare 메서드 사용

    Command.Prepare 메서드를 사용하면, 데이터 원본으로부터 파라미터화된 명령을 반복적으로 수행하는 경우 성능을 향상시킬 수 있습니다. Prepare 메서드를 효과적으로 사용하기 위해서는, Prepare 메서드가 호출되었을 때, 데이터 원본에서 어떠한 작업이 수행되는지 명확하게 알고 있어야 합니다. SQL 서버 2000을 데이터 원본으로 사용한 경우에는, 명령이 호출될 때 암시적으로 최적화 작업이 수행되기 때문에, Prepare 메서드를 호출할 필요가 없습니다. SQL 서버 7.0를 데이터원본을 사용하는 경우에만, Prepare 메서드가 성능상 도움을 줄 수 있습니다.

    명시적으로 스키마와 메타데이터 지정

    ADO.NET 에서는 사용자가 명시적으로 메타데이터 정보를 지정하지 않으면, 자동으로 많은 개체를 추론하여 생성하게 됩니다. 예를 들면,

    • DataAdapter.Fill 메서드는 비어있는 DataSet 개체에 테이블과 열을 생성합니다.
    • CommandBuilder 개체는 단일 테이블에 대한 SELECT 문을 처리하기 위한 DataAdapter 개체의 명령 속성을 생성합니다.
    • CommandBuilder.DeriveParameters 는 Command 개체의 Parameters 컬렉션에 데이터를 입력합니다.

    하지만, 이러한 자동 개체 생성작업이 수행될 때마다 성능에 악영향을 미치게 됩니다. 그러므로, 설계시점과 임의 질의를 수행하는 응용프로그램에서만 제한적으로 자동개체생성 기능을 사용해야 합니다. 가능하다면, 스키마 및 메타데이터 정보는 명시적으로 선언되어야 합니다. DataSet 개체에 테이블과 열을 지정하고, DataAdapter 개체에 Command 속성을 지정하고, Command 개체에 Parameter 정보를 지정하는 작업이 모두 명시적으로 수행되어야 합니다.

    ExecuteScalar 메서드와 ExecuteNonQuery 메서드

    Count(*), Sum(Price), Avg(Quantity)와 같은 함수의 결과값만을 반환해야 한다면, Command.ExecuteScalar 메서드를 사용해야 합니다. Command.ExecuteScalar 메서드는 결과집합의 첫 번째 행, 첫 번째 열만을 스칼라 값으로 반환합니다. DataReader 개체의 ExecuterReader 메서드를 호출하는 경우, ExecuterReader 메서드 실행과 반환된 결과값을 가져오는 두 단계작업을 수행하는 것에 비해서, ExecuteScalar 메서드를 사용하면, 하나의 단계로 처리할 수 있기 때문에, 코드를 매우 간단하게 작성할 수 있으며, 성능도 향상시킬 수 있습니다.

    데이터를 변경하기 위한 INSERT, UPDATE, DELETE 문장과 같이, 결과집합을 반환하지 않는 SQL 문장을 실행하는 경우나 출력 파라미터만 반환하는 질의를 실행하는 경우에는, ExecuteNonQuery 메서드를 사용해야 합니다. ExecuteNonQuery 메서드를 사용하면, 비어있는 DataReader 개체를 생성하기 위한 불필요한 처리절차가 발생하지 않습니다.

    좀 더 자세한 정보는 Command 개체 실행 (영문) 기사를 참조하십시오.

    Null 값 테스트

    null 값을 허용하는 열에 경우, null로 설정된 파라미터값과 동일(=)한지에 대한 비교가 불가능합니다. 대신에, WHERE절에 해당 열이 null인지를 검사하는 구문과 파라미터값이 null인지를 검사하는 구문을 사용해야 합니다. 다음 SQL 문장은 LastName 열과 @LastName 파라미터가 모두 null인 경우를 포함하여, @LastName 파라미터와 일치하는 LastName 열의 행을 반환합니다.

    SELECT * FROM Customers WHERE ((LastName = @LastName) OR (LastName IS NULL AND @LastName IS NULL))

    파라미터 값으로 Null 값 전달

    데이터베이스에 전달할 파라미터의 값을 null로 설정하기 위해서, null(Visual Basic .NET의 nothing)을 사용할 수 없습니다. 대신 DBNull.Value 를 사용해야 합니다. 예를 들면, 다음과 같이 사용해야 합니다.

    'Visual Basic Dim param As SqlParameter = New SqlParameter("@Name", SqlDbType.NVarChar, 20) param.Value = DBNull.Value //C# SqlParameter param = new SqlParameter("@Name", SqlDbType.NVarChar, 20); param.Value = DBNull.Value;

    트랜잭션 처리

    ADO.NET에서는 트랜잭션 모델이 변경되었습니다. ADO에서는 StartTransaction 메서드가 호출되면, 해당 호출 이후에 발생한 어떠한 변경사항도 트랜잭션의 일부로 동작하였습니다. 하지만, ADO.NET에서는 Connection.BeginTransaction 메서드가 호출되면, Command 개체의 Transaction 속성을 연결하기 위해 사용되는 Transaction 개체가 반환됩니다. 트랜잭션 모델 설계 변경을 통해, 하나의 연결에서 여러 개의 트랜잭션을 수행할 수 있게 되었습니다. Command.Transaction 속성이 관련 Connection 개체가 시작되었을 때 발생한 Transaction 개체로 설정되지 않으면, Command 개체는 실행이 실패하게 되고, 예외를 발생시키게 됩니다.

    .NET 프레임워크의 차기 릴리즈에서는 현재 존재하는 분산 트랜잭션을 수작업으로 목록화할 수 있는 기능을 제공할 예정입니다. 이는 풀링된 개체는 하나의 연결을 사용한다는 개체 풀링의 개념을 사용하는 것이지만, 하나의 개체는 여러 개의 개별 트랜잭션에 포함될 수 있습니다. 이러한 기능은 .NET 프레임워크 1.0에서는 지원되지 않습니다.

    트랜잭션에 대한 좀 더 자세한 정보는, 트랜잭션 처리 (영문) 기사나 .NET 데이터 액세스 아키텍쳐 가이드 (영문) 기사를 참조하십시오.

    Connection 개체 사용

    고성능 응용프로그램에서는 사용중인 데이터원본에 최소한의 시간만큼만 연결을 사용해야 하며, 연결 풀링과 같은 성능향상을 위한 기술을 적용해야 합니다. 다음에서는 ADO.NET을 사용하여 데이터원본에 접근하는 경우에, 성능을 극대화하기 위해서 고려해야 하는 몇 가지 팁을 소개합니다.

    연결 풀링

    SQL Server, OLE DB, .NET Framework Data Provider for ODBC 모두 암시적으로 연결풀링을 사용합니다. 연결문자열에서 적절한 속성을 지정함으로써 연결 풀링의 동작을 통제할 수 있습니다. 연결 풀링을 동작방법을 통제하기 위한 자세한 정보는 SQL Server .NET Data Provider에서의 연결풀링 사용 (영문) 기사와 OLE DB .NET Data Provider에서의 연결 풀링 사용 (영문)기사를 참조하십시오.

    DataAdapter 개체에서 연결 최적화

    DataAdapter 개체의 Fill 메서드나 Update 메서드의 경우, 연결이 종료된 경우라면, 자동적으로 관련 Command 속성에 지정된 연결을 엽니다. Fill 메서드나 Update 메서드가 연결을 여는 경우, Fill 메서드나 Update 메서드의 작업이 완료되게 되면, 열린 연결을 자동으로 종료시킵니다. 최적의 성능을 보장하기 위해서, 요청이 발생하는 경우에만 데이터베이스에 대한 연결을 열어야 합니다. 또한 여러 개의 작업을 수행하기 위해 연결이 반복적으로 열고 종료되는 횟수를 줄여주어야 합니다.

    Fill 메서드나 Update 메서드 호출이 한 번만 수행되는 경우에는, Fill 메서드나 Update 메서드가 암시적으로 연결을 열고 종료할 수 있도록 허용하는 것을 권장합니다. 하지만, Fill 메서드나 Update 메서드가 여러 번 호출되는 경우에는, 연결을 명시적으로 열고, 여러 번의 Fill 메서드나 Update 메서드를 호출한 다음, 해당 연결을 명시적으로 종료시키는 방법을 권장합니다.

    또한, 트랜잭션을 사용하는 경우, 트랜잭션이 시작할 때 연결을 명시적으로 연 다음, 커밋된 후에 해당 연결을 명시적으로 종료시키는 방법을 권장합니다. 예를 들어,

    'Visual Basic Public Sub RunSqlTransaction(da As SqlDataAdapter, myConnection As SqlConnection, ds As DataSet) myConnection.Open() Dim myTrans As SqlTransaction = myConnection.BeginTransaction() myCommand.Transaction = myTrans Try da.Update(ds) myTrans.Commit() Console.WriteLine("Update successful.") Catch e As Exception Try myTrans.Rollback() Catch ex As SqlException If Not myTrans.Connection Is Nothing Then Console.WriteLine("An exception of type " & ex.GetType().ToString() & _ " was encountered while attempting to roll back the transaction.") End If End Try Console.WriteLine("An exception of type " & e.GetType().ToString() & " was encountered.") Console.WriteLine("Update failed.") End Try myConnection.Close() End Sub //C# public void RunSqlTransaction(SqlDataAdapter da, SqlConnection myConnection, DataSet ds) { myConnection.Open(); SqlTransaction myTrans = myConnection.BeginTransaction(); myCommand.Transaction = myTrans; try { da.Update(ds); myCommand.Transaction.Commit(); Console.WriteLine("Update successful."); } catch(Exception e) { try { myTrans.Rollback(); } catch (SqlException ex) { if (myTrans.Connection != null) { Console.WriteLine("An exception of type " + ex.GetType() + " was encountered while attempting to roll back the transaction."); } } Console.WriteLine(e.ToString()); Console.WriteLine("Update failed."); } myConnection.Close(); }

    Connection 개체와 DataReader 개체 명시적 종료

    Connection 개체와 DataReader 개체는 사용이 종료되었을 때, 항상 명시적으로 종료시켜야 합니다. 가비지 수집이 발생하면 개체를 정리하고 관련된 연결 및 관련 자원을 해제하는 작업을 수행하지만, 이러한 가비지 수집절차는 필요한 경우에만 발생하게 됩니다. 그러므로, 각 자원에 대해 명시적으로 해제작업을 수행해야만 합니다. 또한 명시적으로 종료되지 않은 Connection 개체는 연결 풀로 반환되지 않을 수도 있습니다. 예를 들어, 더 이상 사용되지 않은 연결이 명시적으로 종료되지 않으면, 최대 풀 크기에 도달한 상태로 해당 연결이 여전히 유효한 경우에만, 연결 풀로 반환되게 됩니다.

    알림 클래스 Finalize 메서드에서 Connection, DataReader, 또는 기타 관리되는 개체에 대한 Close 메서드나 Dispose 메서드를 호출하지 마십시오. 종결자(Finalizer)에서는 해당 클래스에서 직접적으로 소유하고 있는 관리되지 않은 자원에 대해서만 자원해제 작업을 수행합니다. 클래스내부에 관리되지 않은 자원이 포함되어 있지 않다면, 클래스에 Finalize 메서드를 포함시키지 마십시오.

    C#에서 "Using" 구문 사용

    C# 프로그래머는, using 구문을 사용하여, Connection 개체나 DataReader 개체가 항상 명시적으로 종료될 수 있도록 설정할 수 있습니다. using 구문은 자동으로 using 구문의 범위를 벗어난 개체에 대해서 Dispose 메서드를 호출합니다. 예를 들어,

    //C# string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;"; using (SqlConnection conn = new SqlConnection(connString)) { SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers"; conn.Open(); using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1)); } }

    위의 구문은 Microsoft Visual Basic .NET 에서는 사용할 수 없습니다.

    OleDbConnection.State 속성 사용 제한

    연결이 되면, OleDbConnection.State 속성이 DBPROP_CONNECTIONSTATUS 속성에 대한 DATASOURCEINFO 속성을 설정하기 위해서 IDBProperties.GetProperties 를 호출하기 때문에, 데이터원본으로의 라운트트립이 발생하게 됩니다. 즉, State 속성을 체크하는 작업은 많은 비용을 발생시키게 됩니다. 그러므로 State 속성은 꼭 필요한 경우에만 체크해야 합니다. 만약, State 속성을 자주 확인해야 하는 경우라면, 응용프로그램의 성능을 보장하기 위해, OleDbConnection에 대한 StateChange 이벤트가 발생할 때, 적절한 작업을 수행하도록 설정하는 것이 바람직합니다. StateChange 이벤트에 대한 좀 더 자세한 정보는 연결 이벤트 처리 (영문) 기사를 참조하십시오.

    XML 통합

    ADO.NET 에서는 DataSet 내에서 XML 통합기능을 제공하고, SQL 서버 2000과 이후 버전에서 제공하는 XML 지원 기능의 일부를 제공합니다. SQLXML 3.0을 사용하면, SQL서버 2000과 그 이후 버전에서 제공하는 XML 데이터에 대한 개선된 접근방법을 사용할 수 있습니다. 다음에서는 ADO.NET을 사용하여 XML데이터를 처리하는 몇 가지 팁에 대해서 소개합니다.

    DataSet 개체와 XML

    DataSet 개체는 다음과 같은 기능을 통해 XML과의 통합기능을 지원합니다.

    • 스키마를 로드하거나, XSD 스키마로부터 DataSet 개체의 관계형 구조를 로드합니다.
    • XML로부터 DataSet의 항목을 로드합니다.
    • 스키마가 설정되지 않은 경우, XML 문서로부터 DataSet 스키마를 추론합니다.
    • DataSet 항목을 XML로 저장합니다.
    • DataSet 스키마를 XSD 스키마로 저장합니다.
    • DataSet을 사용하여 관계형 표현방식으로 데이터를 처리할 수도 있고, XmlDataDocument를 사용하여 계층형 표현방식으로 데이터를 처리할 수 있으며, 두 가지 방법에는 동기화된 접근방식이 가능합니다.
    알림 DataSet과 XmlDataDocument간에 동기화 접근방법이 가능하기 때문에, DataSet 개체 내에 포함된 데이터에 XPath 질의나 XSLT 변환과 같은 XML 기능을 적용할 수도 있고, 원본 XML을 유지한 상태에서 XML문서의 전체 또는 일부를 관계형으로 표현할 수 있는 기능을 제공합니다.

    DataSet 개체에서 제공하는 XML 지원기능에 대한 자세한 정보는 XML 과 DataSet (영문) 기사를 참조하십시오.

    스키마 추론

    XML 파일을 DataSet 개체로 로드하는 작업을 수행할 때, XSD 스키마로부터 DataSet의 스키마를 로드하거나 데이터를 로드하기 전에 테이블과 열에 대한 정보를 사전에 정의할 수 있습니다. XSD 스키마를 사용할 수 없고, XML 파일 항목에 대한 테이블과 열 정보를 파악할 수 없는 경우에는, XML 문서의 구조를 근거하여 DataSet의 스키마를 추론할 수 있습니다.

    스키마 추론기능은 마이그레이션 도구로서는 매우 유용하게 사용할 수 있지만, 추론 처리절차에 다음과 같은 몇 가지 제약사항이 있기 때문에 응용프로그램의 설계시점에서만 제한적으로 사용되어야 합니다.

    • XML 파일로부터 스키마 정보를 추론하는 추가적인 처리절차가 필요하기 때문에, 응용프로그램의 성능에 악영향을 미치게 됩니다.
    • 추론된 열의 데이터형은 모두 문자열(string)로 지정됩니다.
    • 추론 처리절차는 확정이지 않습니다. 즉, 의도된 스키마가 아니라, XML 파일의 항목의 구성을 근거로 하여 추론 처리절차를 수행하게 됩니다. 결국, 동일한 의도된 스키마를 근거로 하여 두 개의 XML 파일을 생성하였다면, XML 항목이 서로 다르기 때문에 전혀 다른 두 개의 추론된 스키마가 생성될 수 있습니다.

    좀 더 자세한 정보는, XML로부터 DataSet 관계형 구조 추론 (영문) 기사를 참조합니다.

    SQL Server FOR XML 질의

    SQL 서버 2000의 FOR XML 질의의 결과값을 반환하는 경우, .NET Framework Data Provider for SQL Server의 SqlCommand.ExecuteXmlReader 메서드를 사용하여 XmlReader 개체를 직접적으로 생성할 수 있습니다.

    SQLXML 관리되는 클래스

    .NET 프레임워크에는 SQL 서버 2000의 XML 지원 기능을 제공하는 클래스가 포함되어 있습니다. Microsoft.Data.SqlXml 네임스페이스에 포함되어 있는 클래스를 사용하면, XPath 질의를 실행하고, 데이터를 XSLT와 같은 특정한 형식으로 변환하기 위해, XML 템플릿 파일을 사용할 수 있습니다.

    SQLXML 관리되는 클래스는 XML for Microsoft SQL Server 2000 (SQLXML 2.0)에 포함되어 있으며, XML for Microsoft SQL Server 2000 Web Release 2 (SQLXML 2.0) 기사에서 다운로드 받을 수 있습니다.

    추가 유용한 팁

    다음에서는 ADO.NET 코드를 작성할 때 고려할 수 있는 몇 가지 일반적인 팁을 소개합니다.

    자동 증가 값 충돌 피하기

    대부분의 데이터원본과 같이, DataSet 개체도 새로운 행이 추가될 때마다 자동적으로 값을 증가시키는 식별자 열 기능을 제공합니다. 데이터원본에서 자동증가 열로 지정된 열과 함께, DataSet 개체에 자체에서 제공하는 자동증가 열 기능을 사용하는 경우, DataSet에 행이 추가될 때 발생하는 자동증가 값과 데이터원본에 행이 추가될 때 발생하는 자동증가 값 사이에 차이가 발생하지 않도록 주의해야 합니다.

    예를 들어, CustomerID가 자동증가 기본 키 열로 설정된 테이블의 경우를 살펴보겠습니다. 테이블에 고객정보가 2 건 입력되면, 자동증가 열인 CustomerID는 각각 1과 2로 설정됩니다. 그 다음, DataAdapter의 Update 메서드를 사용하여, 두번째 행만 데이터베이스에 입력하게 하면, 데이터베이스에 새로 추가된 행에는 자동증가 열인 CustomerID 열의 값이 1로 입력됩니다. DataSet에 설정되어 있는 2와는 서로 다른 값으로 설정되는 문제가 발생합니다. 다시, DataAdapter에서 데이터베이스에 있는 두 번째 행을 DataSet에 채우게 되면, 이미 CustomerID가 1인 행이 DataSet 내부에 존재하기 때문에 제약조건 위반 오류가 발생합니다.

    이러한 문제점을 해결하기 위해서는, 데이터원본과 DataSet 개체에서 동시에 자동 증가 열을 사용하는 경우에는, DataSet의 자동증가열의 AutoIncrementStep 을 -1로 설정하고, AutoIncrementSeed 은 0으로 설정하고, 데이터원본의 자동증가 열의 식별자 값은 1로부터 시작하여 점점 값이 커지도록 설정하게 됩니다. 결국, DataSet 개체는 자동증가 열 값을 음수로 생성하기 때문에, 데이터원본에 의해서 생성된 자동증가 열의 양수 값과 절대 충돌이 발생하지 않습니다. 다른 대안으로는 자동증가열대신 GUID 열을 사용하는 방법이 있습니다. GUID 값을 생성하는 알고리즘은 데이터원본에서 생성된 값과 DataSet에서 생성된 값이 절대로 동일하게 생성되지 않도록 보장해 줍니다.

    자동증가 열을 사용하는 이유가 유일한 값을 지정할 목적 외에 다른 이유가 없는 경우에는, 자동증가 열대신 GUID 열을 사용할 것을 고려해 보아야 합니다. GUID 값은 유일하게 식별가능하며, 자동증가 열 값을 사용하는 경우에 발생하는 추가처리작업을 할 필요가 없습니다.

    데이터 원본으로부터 자동증가열 값을 조회하기 위한 사례는 식별자 또는 자동증가숫자 값 조회 (영문) 기사를 참조하십시오.

    긍정적 동시성 위반 점검

    DataSet은 설계상 데이터원본과 비연결상태이기 때문에, 긍정적인 동시성 모델을 사용하여, 다중 클라이언트에서 데이터를 동시에 변경할 때 응용프로그램에서 충돌이 발생하지 않도록 보장해야 합니다.

    긍정적인 동시성 위반여부를 테스트하기 위해서는 몇 가지 방법을 사용할 수 있습니다. 첫째는, 테이블에 timestamp 열을 포함하는 것입니다. 다른 방법으로는, SQL 문장에 WHERE 절을 사용하여, 데이터베이스에 원본 열값을 가지고 있는 행이 존재하는지 확인하는 방법이 있습니다.

    긍정적 동시성에 대한 코드 예제와 관련된 내용은 긍정적 동시성 (영문) 기사를 참조하십시오.

    멀티스레드 프로그래밍

    ADO.NET은 성능, 확장성, 생산성 측면에서 최적화되어 있습니다. ADO.NET 개체는 자원에 잠금설정을 하지 않으며, 단일 스레드에서만 사용해야 합니다. 단, DataSet 개체에서 여러 개의 읽기 작업하기 위해 스레드 안정성을 지원하는 경우는 예외입니다. 하지만, 쓰기작업을 하는 동안에는 DataSet 개체에 대해서 잠금이 설정되어야 합니다.

    꼭 필요한 경우에만 COM Interop을 사용하여 ADO에 접근

    ADO.NET은 대부분의 응용프로그램에 적용할 수 있는 최적의 솔루션으로 설계되었습니다. 하지만, ADOMD와 같은 ADO 개체를 사용해야 하는 응용프로그램이 있을 수 있습니다. 응용프로그램에서 ADO 개체를 사용하기 위해서는, COM Interop를 사용해야 합니다. ADO 개체를 사용하기 위해서 COM Interop을 사용하면, 성능상에 부하가 발생하게 됩니다. 응용프로그램을 설계할 때, ADO 개체를 설계에 포함시키기 전에, 먼저 ADO.NET을 사용하여 설계상 요구조건을 충족시킬 수 있는지 점검해야 합니다.

크리에이티브 커먼즈 라이선스
Creative Commons License

'General Tech.' 카테고리의 다른 글

땅을 팔려면 포크레인으로~  (0) 2008/01/29
WBS(Work Breakdown Structure)  (0) 2008/01/29
ADO.NET 표준사례  (0) 2008/01/09
Bill Gates 2008 CES Keynote Speech Part 4  (0) 2008/01/08
2008 CES Keynote 'Bill Gates'  (0) 2008/01/08
Bill Gates 2008 CES Keynote Speech Part 3  (0) 2008/01/08
Posted by -세티-
Constructor() ───── InitializeEvent()

Fom Load()   ───── Init Form()─────InitBody()────── InitGrid()
                                                       │                           │
                                                       │                           └─── InitCombo()
                                                       │
                                                       ├── InitCtrl()
                                                       │
                                                       │
                                                       └── InitTreeView()

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-
Assembly DisplayName, Loading, Configuration File, Probing

http://www.ensimple.net/enSimple/show.aspx?cnum=293&b_id=study_csharp&page=1
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-

일하다가 잠시 쉴겸 인터넷을 보는데 눈에 띄는 기사가 보였습니다.

[간판 바꾸고 훤해진 상가… 거리 분위기도 '산뜻']

사진을 보자마자 떠오른 단어가 '혁신(innovation)' 이었습니다.

innovation의 사전적 의미를 보니 '생산을 확대하기 위해 노동, 토지등 생산적 요소의 편성을 변화시키거나 새로운 생산 요소를 도입하는 행위' 라고 되어 있네요.

사진만 봐도 뭔가 산뜻해지고, 전혀 다른 느낌이 드는 것은 저뿐만이 아닌 것 같습니다.
혁신을 하기 위해 얼마나 많은 이해 관계자들과 충돌했을지도 충분히 상상이 되네요.

사람은 이미 익숙해진 자신의 것을 새로운 것으로 변경하는데 엄청난 스트레스를 받는다고 합니다.
스트레스를 받더라도 꾸준히 바꾸고, 변경하고(물론 더 나은 방향으로요.) 그렇게 개선된다면
개인은 물론이고 이 사회도 더 살기 좋아지지 않을까 하는 생각이 듭니다.
저 사진 한장이 잊혀져 가던 부분을 다시 기억나게 해주네요.

스트레스 받는 모든 분들...~ 즐기면서 스트레스 받자구요.ㅎㅎ

크리에이티브 커먼즈 라이선스
Creative Commons License

'Thinking' 카테고리의 다른 글

제 3회 천문노트 정기관측회 안내  (0) 2008/01/20
내가 너의 곁에 잠시 살았다는 걸  (0) 2008/01/17
한 장의 사진, 그리고 생각  (0) 2008/01/08
little Star-The Elegants 1958  (0) 2007/12/28
개발을 하다보면...  (0) 2007/12/23
세상은 변해가는 것.  (0) 2007/12/17
Posted by -세티-
TAG 혁신

function deco(InStr)
    {
          var base64_decodetable = new Array (
                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
                52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255, 255, 255, 255,
                255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12,  13,  14,
                15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
                255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
                41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255
          );
          var result = "";
          var len = what.length;
          var x, y;
          var ptr = 0;

          while( !isNaN( x = what.charCodeAt( ptr++ ) ) )
          {
                if( x == 13 || x == 10 )
                      continue;

                if( ( x > 127 ) || (( x = base64_decodetable[x] ) == 255) )
                      return false;
                if( ( isNaN( y = what.charCodeAt( ptr++ ) ) ) || (( y = base64_decodetable[y] ) == 255) )
                      return false;

                result += String.fromCharCode( (x << 2) | (y >> 4) );

                if( (x = what.charCodeAt( ptr++ )) == 61 )
                {
                      if( (what.charCodeAt( ptr++ ) != 61) || (!isNaN(what.charCodeAt( ptr ) ) ) )
                            return false;
                }
                else
                {
                      if( ( x > 127 ) || (( x = base64_decodetable[x] ) == 255) )
                            return false;
                      result += String.fromCharCode( (y << 4) | (x >> 2) );
                      if( (y = what.charCodeAt( ptr++ )) == 61 )
                      {
                            if( !isNaN(what.charCodeAt( ptr ) ) )
                                  return false;
                      }
                      else
                      {
                            if( (y > 127) || ((y = base64_decodetable[y]) == 255) )
                                  return false;
                            result += String.fromCharCode( (x << 6) | y );
                      }
                }
          }
          return result;
    }

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-

손쉬운 스케줄 관리방법(조엘 온 소프트웨어 에서...)

1. 엑셀을 사용할 것.
    - 제가 보기에도 엑셀만큼 접근성이 좋고, 빠르게 업데이트 하여 팀원 모두가 공유할 만한 프로그램은 못봤습니다.
   

2. 단순하게 만들것.(개발자가 여러명일 경우 쉬트별로 작성)
    - 그렇지 않아도 복잡한 화면 개발하느라 머리 아픈데, 그것도 모라라서 복잡한 스케줄 관리 화면을 또 본다면....아 치가 떨립니다.
    - 단순한게 최고!! 입니다.

3. 하나의 기능은 여러 개의 작업으로 분해할 것
    - 예) 맞춤법 검사 기능 -> 여러 단계의 작업목록을 만든다.
    - 기능을 분해할 수록 만들어질 기능에 대한 요소가 명확해지고, 일정도 보다 정확하게 산출이 될 겁니다.
    - 우리는 이미 배보다 배꼽이 더 큰 상황을 많이 경험했으니깐요.^^;

4. 개발자가 직접 스케줄을 작성할 것.
   - 자기 스케줄은 자기가 직접 작성해야죠....^^; 안 그러면 피박 씁니다.

5. 작업단위를 세분화 한다.
    - 작업량은 날짜가 아닌 시간 단위로 계산 할 것.
    - 타임으로 계산하고 시간을 합쳐서 날짜단위로 기록한 후 도표화 하면 보기 편합니다.

6. 최초추정시간과 현재추정시간을 지속적으로 추적할 것
    - 처음 추정시간은 언제나 늘 그렇듯 수많은 인터럽트로 인해 시간이 더 오래 걸리기도 합니다.
    - 그 중에는 예측 불가능한 요소들도 많을 것이고요~ 결국 현재추정시간을 적다보면 언젠가는 명확해 지겠지요~

7. 경과시간을 매일 업데이트 한다.
   - 매일 업데이트 하는 것이 일주일 뒤에 업데이트 하는 것 보다는 덜 피곤할 겁니다.^^*

8. 디버깅 시간을 반드시 포함 할 것.
   - 개발하면서 디버깅 시간을 고려하지 않는다는 것은 자살 행위 입니다.
   - 디버깅 시간은 때론 개발 시간의 두 배를 잡아 먹기도 하니깐요.^^
   - 하지만 원칙적으로는 단위개발 - 디버깅 이 순서로는 맞습니다.

9. 통합 시간을 고려할 것.
   - 통합시간은 꼭 잡아야 합니다. 의외로 통합과정에서 밤새기도 하거든요.

10. 여분의 시간을 포함 시킬것(버퍼 타임)
   - 버퍼 타임은 추가적인 또는 변경되는 요구 조건을 수용하기 위한 타임입니다.
   - 그리고 일종의 보험 성격인데요, 개발 시간이 부족할 경우 버퍼 타임을 희생할 수 있을 겁니다.
   - 야금야금 말이죠.

11. 관리자가 시간을 단축할 것을 고려하여 새로운 컬럼(릭의 추정시간)을 추가한다.
   - 마지막으로 스케줄을 작성하다보니 정말 요소에 비해 개발 시간이 절대 부족한 경우도 있을 겁니다.
   - 이런 경우에는 어쩔수 없이 가짜 컬럼을 만듭니다.
   - 가짜라고 해서 거짓말은 아니고요... 릭이라는 가상의 인물을 만들고 그 사람이 작업할 량을 할당해 주라는 겁니다.
   - 필수가 아닌 옵션으로 말이죠.^^

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by -세티-

세티는?

About me? 2008/01/01 03:09
세티

10년뒤 난 무얼 하고 있을까? 궁금해.^^


76년생, 남자
사는 곳 : 서울 마포
학력 : 고려대학교 컴퓨터정보통신대학원 소프트웨어공학 석사
취미 : 하늘보기, 사람 만나기, 드라이브 하기(주로 양평으로) 등
좋아하는 것 : 북카페, 비, 밤 하늘의 별, 자동차, 사색, 호수, 바다 등
존경하는 사람 : 칼 세이건, 세종대왕, 그리고 내 주변의 모든 지인들.

좋아하는 음식 : 몸에 안 좋은 거 대부분...(콜라, 라면 등)
좋아하는 술 : 없음.

하는 일 : 소프트웨어 개발자
일했던 곳 : 호서전문학교, 인브레인, 세스코, Daum 등
알고 있는 소프트웨어 관련 지식 : C#, ASP.NET, XML, VB, ASP, JavaScript(JSON), CSS, HTML(웹 표준) 
알고 있는 서버 관리 : Windows 2003 Server, MS-SQL 2005(2008), Vista, Windows 7
알고 있는 방법론 및 그 외 : CBD, MSF-CD, CMMI, UML 기타 잡다구리...
강의 경험 : 소프트웨어 진흥협회(ASP.NET 강의)
                Daum DevDay UX and 실버라이트 세미나 발표
                호서전문학교(웹 프로그래밍 강의)
                제1회소프트웨어아키텍트 대회(UX 아키텍처 주제로 발표)
수상 경험 : Microsoft IT Hero Blog상 (2008)
                Microsoft Visual C# MVP (2009)

10년 뒤의 꿈 : 나만의 독립 사업체( 사람과 학문을 위한 소프트웨어 만들기 )
20년 뒤의 꿈 : 교외에 나만의 천문대 만들기
30년 뒤의 꿈 : 뒤돌아 보았을 때 하늘을 우러러 한점 부끄러움 없기를 바라는 삶
40년 뒤의 꿈 : 딱 30년 더 살기 위해 발버둥 치는 것.

관심분야 : 소프트웨어 지식을 천문학에 응용하는 분야.

기타 : 한국아마추어천문학회(KAAS) 정보국장 (2010)
         한국아마추어천문학회 서울지부 정보부장 (2008 ~ 2010)
         고수닷넷 부시삽 역임
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License

'About me?' 카테고리의 다른 글

세티는?  (0) 2008/01/01
Posted by -세티-