๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

๐Ÿค Chapter 6. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ

๐Ÿฅ• ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ์„ธ ๊ฐ€์ง€ ์Šคํƒ€์ผโ€‹

๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์„ธ ๊ฐ€์ง€ ์Šคํƒ€์ผ์ด ์žˆ๋‹ค.

  • ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
  • ์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
  • ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ

ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ์—์„œ ํ•˜๋‚˜ ๋˜๋Š” ๋‘˜, ์‹ฌ์ง€์–ด ์„ธ ๊ฐ€์ง€ ์Šคํƒ€์ผ ๋ชจ๋‘๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ์ •์˜โ€‹

ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์‹œ์Šคํ…œ(SUT)์— ์ž…๋ ฅ์„ ๋„ฃ๊ณ  ์ƒ์„ฑ๋˜๋Š” ์ถœ๋ ฅ์„ ์ ๊ฒ€ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ์€ ์ „์—ญ ์ƒํƒœ๋‚˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ์—๋งŒ ์ ์šฉ๋˜๋ฏ€๋กœ ๋ฐ˜ํ™˜ ๊ฐ’๋งŒ ๊ฒ€์ฆํ•˜๋ฉด ๋œ๋‹ค.

์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
public class PriceEngine {
public decimal CalculateDiscount(params Product[] products) {
decimal discount = products.Length * 0.01m;
return Math.Min(discount, 0.2m);
}
}

[Fact]
public void Discount_of_two_products() {
var product1 = new Product("Hand wash");
var product2 = new Product("Shampoo");
var sut = new PriceEngine();

decimal discount = sut.CalculateDiscount(product1, product2);

Assert.Equal(0.02m, discount);
}

CalculateDiscount() ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๋Š” ๋ฐ˜ํ™˜๋œ ํ• ์ธ, ์ฆ‰ ์ถœ๋ ฅ ๊ฐ’๋ฟ์ด๋‹ค.

์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ์€ ํ•จ์ˆ˜ํ˜•์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค. ์ด ์ด๋ฆ„์€ ๋ถ€์ž‘์šฉ ์—†๋Š” ์ฝ”๋“œ ์„ ํ˜ธ๋ฅผ ๊ฐ•์กฐํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์ธ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋ฟŒ๋ฆฌ๋ฅผ ๋‘๊ณ  ์žˆ๋‹ค.

๐ŸŽˆ ์ƒํƒœ ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ ์ •์˜โ€‹

์ƒํƒœ ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ์€ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„ ์‹œ์Šคํ…œ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ์—์„œ ์ƒํƒœ๋ผ๋Š” ์šฉ์–ด๋Š” SUT๋‚˜ ํ˜‘๋ ฅ์ž ์ค‘ ํ•˜๋‚˜, ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ํŒŒ์ผ ์‹œ์Šคํ…œ ๋“ฑ๊ณผ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€ ์˜์กด์„ฑ์˜ ์ƒํƒœ ๋“ฑ์„ ์˜๋ฏธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
public class Order {
private readonly List<Product> _products = new List<product>();
public IReadOnlyList<Product> Products => _products.ToList();

public void AddProduct(Product product) {
_products.Add(product);
}
}

[Fact]
public void Adding_a_product_to_an_order() {
var product = new Product("Hand wash");
var sut = new Order();

sut.AddProduct(product);

Assert.Equal(1, sut.Products.Count);
Assert.Equal(product, sut.Products[0]);
}

ํ…Œ์ŠคํŠธ๋Š” ์ƒํ’ˆ์„ ์ถ”๊ฐ€ํ•œ ํ›„ Products ์ปฌ๋ ‰์…˜์„ ๊ฒ€์ฆํ•œ๋‹ค. ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์˜ ์˜ˆ์ œ์™€ ๋‹ฌ๋ฆฌ, AddProduct()์˜ ๊ฒฐ๊ณผ๋Š” ์ฃผ๋ฌธ ์ƒํƒœ์˜ ๋ณ€๊ฒฝ์ด๋‹ค.

๐ŸŽˆ ํ†ต์‹  ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ ์ •์˜โ€‹

ํ†ต์‹  ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ์€ ๋ชฉ์„ ์‚ฌ์šฉํ•ด ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์‹œ์Šคํ…œ๊ณผ ํ˜‘๋ ฅ์ž ๊ฐ„์˜ ํ†ต์‹ ์„ ๊ฒ€์ฆํ•œ๋‹ค.

ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ
[Fact]
public void Sending_a_greetings_email() {
var emailGatewayMock = new Mock<IEmailGateway>();
var sut = new Controller(emailGatewayMock.Object);

sut.GreetUser("user@email.com");

emailGatewayMock.Verify(
x => x.SendGreetingsEmail("user@email.com"),
Times.Once
);
}

๐Ÿฅ• ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ ๋น„๊ตโ€‹

๐ŸŽˆ ํšŒ๊ท€ ๋ฐฉ์ง€์™€ ํ”ผ๋“œ๋ฐฑ ์†๋„ ์ง€ํ‘œ๋กœ ์Šคํƒ€์ผ ๋น„๊ตํ•˜๊ธฐโ€‹

ํšŒ๊ท€ ๋ฐฉ์ง€ ์ง€ํ‘œ๋Š” ํŠน์ • ์Šคํƒ€์ผ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. ํšŒ๊ท€ ๋ฐฉ์ง€ ์ง€ํ‘œ๋Š” ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ํŠน์„ฑ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค.

  • ํ…Œ์ŠคํŠธ ์ค‘์— ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ์˜ ์–‘
  • ์ฝ”๋“œ ๋ณต์žก๋„
  • ๋„๋ฉ”์ธ ์œ ์˜์„ฑ

๋ณดํ†ต ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŽ๋“  ์ ๋“  ์›ํ•˜๋Š” ๋Œ€๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ์Šคํƒ€์ผ๋„ ์ด ๋ถ€๋ถ„์—์„œ ๋„์›€์ด ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ฝ”๋“œ ๋ณต์žก๋„์™€ ๋„๋ฉ”์ธ ์œ ์˜์„ฑ ์—ญ์‹œ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. ํ†ต์‹  ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ์—๋Š” ์˜ˆ์™ธ๊ฐ€ ํ•˜๋‚˜ ์žˆ๋‹ค. ๋‚จ์šฉํ•˜๋ฉด ์ž‘์€ ์ฝ”๋“œ ์กฐ๊ฐ์„ ๊ฒ€์ฆํ•˜๊ณ  ๋‹ค๋ฅธ ๊ฒƒ์€ ๋ชจ๋‘ ๋ชฉ์„ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ ํ”ผ์ƒ์ ์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ์ •์ ์ธ ํŠน์ง•์ด ์•„๋‹ˆ๋ผ ๊ธฐ์ˆ ์„ ๋‚จ์š”ํ•˜๋Š” ๊ทน๋‹จ์ ์ธ ์‚ฌ๋ก€๋‹ค.

ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ๊ณผ ํ…Œ์ŠคํŠธ ํ”ผ๋“œ๋ฐฑ ์†๋„ ์‚ฌ์ด์—๋Š” ์ƒ๊ด€๊ด€๊ณ„๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€ ์˜์กด์„ฑ๊ณผ ๋–จ์–ด์ ธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์˜์—ญ์— ์žˆ๋Š” ํ•œ, ๋ชจ๋“  ์Šคํƒ€์ผ์€ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์†๋„๊ฐ€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค. ๋ชฉ์€ ๋Ÿฐํƒ€์ž„์— ์ง€์—ฐ ์‹œ๊ฐ„์ด ์ƒ๊ธฐ๋Š” ํŽธ์ด๋ฏ€๋กœ ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์•ฝ๊ฐ„ ๋‚˜์  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜๋งŒ ๊ฐœ ์ˆ˜์ค€์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ณ„๋กœ ์ฐจ์ด๋Š” ์—†๋‹ค.

๐ŸŽˆ ๋ฆฌํŒฉํ„ฐ๋ง ๋‚ด์„ฑ ์ง€ํ‘œ๋กœ ์Šคํƒ€์ผ ๋น„๊ตํ•˜๊ธฐโ€‹

๋ฆฌํŒฉํ„ฐ๋ง ๋‚ด์„ฑ์€ ๋ฆฌํŒฉํ„ฐ๋ง ์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ๊ฑฐ์ง“ ์–‘์„ฑ ์ˆ˜์— ๋Œ€ํ•œ ์ฒ™๋„๋‹ค. ๊ฒฐ๊ตญ ๊ฑฐ์ง“ ์–‘์„ฑ์€ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์ž‘์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ์˜ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๊ฒฐํ•ฉ๋œ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ๋‹ค.

์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ์—๋งŒ ๊ฒฐํ•ฉ๋˜๋ฏ€๋กœ ๊ฑฐ์ง“ ์–‘์„ฑ ๋ฐฉ์ง€๊ฐ€ ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•˜๋‹ค. ์ด;๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๊ฒฐํ•ฉ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์ผ ๋•Œ๋ฟ์ด๋‹ค.

์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฑฐ์ง“ ์–‘์„ฑ์ด ๋˜๊ธฐ ์‰ฝ๋‹ค. ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋Š” ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ ์™ธ์—๋„ ํด๋ž˜์Šค ์ƒํƒœ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•œ๋‹ค. ์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ํฐ API ๋…ธ์ถœ ์˜์—ญ์— ์˜์กดํ•˜๋ฏ€๋กœ, ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ๊ณผ ๊ฒฐํ•ฉํ•  ๊ฐ€๋Šฅ์„ฑ๋„ ๋” ๋†’๋‹ค.

ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ํ—ˆ์œ„ ์ •๋ณด์— ๊ฐ€์žฅ ์ทจ์•ฝํ•˜๋‹ค. ํ…Œ์ŠคํŠธ ๋Œ€์—ญ์œผ๋กœ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ๋Œ€๋ถ€๋ถ„ ๊นจ์ง€๊ธฐ ์‰ฝ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋Š” ์ƒํ˜ธ ์ž‘์šฉ์„ ํ™•์ธํ•˜๊ณ  ํ•ด๋‹น ์ƒํ˜ธ ์ž‘์šฉ์˜ ๋ถ€์ž‘์šฉ์ด ์™ธ๋ถ€ ํ™˜๊ฒฝ์— ๋ณด์ด๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ชฉ์ด ๊ดœ์ฐฎ๋‹ค.

๐ŸŽˆ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ ์ง€ํ‘œ๋กœ ์Šคํƒ€์ผ ๋น„๊ตํ•˜๊ธฐโ€‹

์œ ์ง€ ๋ณด์ˆ˜์„ฑ์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ์œ ์ง€๋น„๋ฅผ ์ธก์ •ํ•˜๋ฉฐ, ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ํŠน์„ฑ์œผ๋กœ ์ •์˜ํ•œ๋‹ค.

  • ํ…Œ์ŠคํŠธ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์–ผ๋งˆ๋‚˜ ์–ด๋ ค์šด๊ฐ€?
  • ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์–ผ๋งˆ๋‚˜ ์–ด๋ ค์šด๊ฐ€?

ํ…Œ์ŠคํŠธ๊ฐ€ ํฌ๋ฉด, ํ•„์š”ํ•  ๋•Œ ํŒŒ์•…ํ•˜๊ธฐ๋„ ๋ณ€๊ฒฝํ•˜๊ธฐ๋„ ์–ด๋ ค์šฐ๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€ ์˜์กด์„ฑ๊ณผ ์ง์ ‘ ์ž‘๋™ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋ฒ„ ์žฌ๋ถ€ํŒ…, ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋“ฑ๊ณผ ๊ฐ™์ด ์šด์˜ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค.

๋‹ค๋ฅธ ๋‘ ๊ฐ€์ง€ ์Šคํƒ€์ผ๊ณผ ๋น„๊ตํ•˜๋ฉด, ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€์žฅ ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ ์šฉ์ดํ•˜๋‹ค. ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์งง๊ณ  ๊ฐ„๊ฒฐํ•˜๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์‰ฝ๋‹ค. ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์˜ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋Š” ์ „์—ญ ์ƒํƒœ๋‚˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๋ฆฌ ์—†์œผ๋ฏ€๋กœ, ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ๋‹ค๋ฃจ์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ๊ฐ€์ง€ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ ๋ชจ๋‘์˜ ์ธก๋ฉด์—์„œ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€์žฅ ์ข‹๋‹ค.

์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋ณด๋‹ค ์œ ์ฆค ๋ณด์ˆ˜๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค. ์ƒํƒœ ๊ฒ€์ฆ์€ ์ข…์ข… ์ถœ๋ ฅ ๊ฒ€์ฆ๋ณด๋‹ค ๋” ๋งŽ์€ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋งŽ์€ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๋Š” ์ƒํƒœ ๊ฒ€์ฆ
[Fact]
public void Adding_a_comment_to_an_article() {
var sut = new Article();
var text = "Comment text";
var author = "John Doe";
var now = new DateTime(2019, 4, 1);

sut.AddComment(text, author, now);

Assert.Equal(1, sut.Comments.Count);
Assert.Equal(text, sut.Comments[0].Text);
Assert.Equal(author, sut.Comments[0].Author);
Assert.Equal(now, sut.Comments[0].DateCreated);
}

์ด ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์ˆœํ•˜๊ณ  ๋Œ“๊ธ€์ด ํ•˜๋‚˜๋งŒ ์žˆ์ง€๋งŒ, ๊ฒ€์ฆ๋ถ€๋Š” ๋„ค ์ค„์— ๊ฑธ์ณ ์žˆ๋‹ค. ์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ์ข…์ข… ํ›จ์‹  ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ ํฌ๊ธฐ๊ฐ€ ๋Œ€ํญ ์ปค์งˆ ์ˆ˜ ์žˆ๋‹ค.

ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ์œ ์ง€ ๋ณด์ˆ˜์„ฑ ์ง€ํ‘œ์—์„œ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์™€ ์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋ณด๋‹ค ์ ์ˆ˜๊ฐ€ ๋‚ฎ๋‹ค. ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์—๋Š” ํ…Œ์ŠคํŠธ ๋Œ€์—ญ๊ณผ ์ƒํ˜ธ ์ž‘์šฉ ๊ฒ€์ฆ์„ ์„ค์ •ํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋Š” ๊ณต๊ฐ„์„ ๋งŽ์ด ์ฐจ์ง€ํ•œ๋‹ค. ๋ชฉ์ด ์‚ฌ์Šฌ ํ˜•ํƒœ๋กœ ์žˆ์„ ๋•Œ ํ…Œ์ŠคํŠธ๋Š” ๋” ์ปค์ง€๊ณ  ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค.

๐ŸŽˆ ์Šคํƒ€์ผ ๋น„๊ตํ•˜๊ธฐ: ๊ฒฐ๋ก โ€‹

์„ธ ๊ฐ€์ง€ ์Šคํƒ€์ผ ๋ชจ๋‘ ํšŒ๊ท€ ๋ฐฉ์ง€๊ณผ ํ”ผ๋“œ๋ฐฑ ์†๋„ ์ง€ํ‘œ์—์„œ๋Š” ์ ์ˆ˜๊ฐ€ ๊ฐ™๋‹ค.

์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€์žฅ ๊ฒฐ๊ณผ๊ฐ€ ์ข‹๋‹ค. ์ด ์Šคํƒ€์ผ์€ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ๊ณผ ๊ฑฐ์˜ ๊ฒฐํ•ฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฆฌํŒฉํ„ฐ๋ง ๋‚ด์„ฑ์„ ์ ์ ˆํžˆ ์œ ์ง€ํ•˜๊ณ ์ž ์ฃผ์˜๋ฅผ ๋งŽ์ด ๊ธฐ์šธ์ผ ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ด๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋Š” ๊ฐ„๊ฒฐํ•˜๊ณ  ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€ ์˜์กด์„ฑ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€ ๋ณด์ˆ˜๋„ ์‰ฝ๋‹ค.

์ถœ๋ ฅ ๊ธฐ๋ฐ˜์ƒํƒœ ๊ธฐ๋ฐ˜ํ†ต์‹  ๊ธฐ๋ฐ˜
๋ฆฌํŒฉํ„ฐ๋ง ๋‚ด์„ฑ์„ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋…ธ๋ ฅ๋‚ฎ์Œ์ค‘๊ฐ„์ค‘๊ฐ„
์œ ์ง€๋น„๋‚ฎ์Œ์ค‘๊ฐ„๋†’์Œ

์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์™€ ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ๋‘ ์ง€ํ‘œ ๋ชจ๋‘ ์ข‹์ง€ ์•Š๋‹ค. ์œ ์ถœ๋œ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๊ฒฐํ•ฉํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ณ , ํฌ๊ธฐ๋„ ์ปค์„œ ์œ ์ง€๋น„๊ฐ€ ๋งŽ์ด ๋“ ๋‹ค.
๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ•ญ์ƒ ๋‹ค๋ฅธ ๊ฒƒ๋ณด๋‹ค ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์„ ํ˜ธํ•˜๋ผ. ํ•˜์ง€๋งŒ ์•ˆํƒ€๊น๊ฒŒ๋„ ๋งํ•˜๊ธฐ๋Š” ์‰ฌ์›Œ๋„ ํ–‰ํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค. ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ์€ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ๋Œ€๋ถ€๋ถ„์˜ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—๋Š” ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿฅ• ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜ ์ดํ•ดโ€‹

๐ŸŽˆ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€?โ€‹

์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ์€ ํ•จ์ˆ˜ํ˜•์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค. ๊ธฐ๋ฐ˜ ์ œํ’ˆ ์ฝ”๋“œ๋ฅผ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ด์šฉํ•ด ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ˆ˜ํ•™์  ํ•จ์ˆ˜(์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ๊ณ ๋„ ํ•จ)๋ฅผ ์‚ฌ์šฉํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค. ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋Š” ์ˆจ์€ ์ž…์ถœ๋ ฅ์ด ์—†๋Š” ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์„œ๋“œ)๋‹ค. ์ˆ˜ํ•™์  ํ•จ์ˆ˜์˜ ๋ชจ๋“  ์ž…์ถœ๋ ฅ์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„, ์ธ์ˆ˜, ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค. ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ํšŸ์ˆ˜์— ์ƒ๊ด€์—†์ด ์ฃผ์–ด์ง„ ์ž…๋ ฅ์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•œ๋‹ค.

public decimal CalculateDiscount(Product[] products) {
decimal discount = products.Length + 0.01m;
return Math.Min(discount, 0.2m);
}

์ด ๋ฉ”์„œ๋“œ๋Š” ํ•˜๋‚˜์˜ ์ž…๋ ฅ๊ณผ ํ•˜๋‚˜์˜ ์ถœ๋ ฅ์ด ์žˆ์œผ๋ฉฐ, ๋‘˜ ๋‹ค ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋ช…์‹œ๋ผ ์žˆ๋‹ค. ์ด๋กœ์จ CalculateDiscount()๋Š” ์ˆ˜ํ•™์  ํ•จ์ˆ˜๊ฐ€ ๋œ๋‹ค.

//     ์ถœ๋ ฅ     ์ด๋ฆ„               ์ž…๋ ฅ
public decimal CalculateDiscount(Product[] products)

์ˆจ์€ ์ž…์ถœ๋ ฅ์ด ์—†๋Š” ๋ฉ”์„œ๋“œ๋Š ์ˆ˜ํ•™์—์„œ ๋งํ•˜๋Š” ํ•จ์ˆ˜์˜ ์ •์˜๋ฅผ ์ค€์ˆ˜ํ•˜๊ธฐ ๋–„๋ฌธ์— ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋ผ๊ณ  ํ•œ๋‹ค.
์ž…์ถœ๋ ฅ์„ ๋ช…์‹œํ•œ ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋Š” ์ด์— ๋”ฐ๋ฅด๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์งง๊ณ  ๊ฐ„๊ฒฐํ•˜๋ฉฐ ์ดํ•ดํ•˜๊ณ  ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ๋‹ค. ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ ์œ ํ˜•์€ ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋ฟ์ด๋‹ค. ์ด๋Š” ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์ด ๋›ฐ์–ด๋‚˜๊ณ  ๊ฑฐ์ง“ ์–‘์„ฑ ๋นˆ๋„๊ฐ€ ๋‚ฎ๋‹ค.

๋ฐ˜๋ฉด์— ์ˆจ์€ ์ž…์ถœ๋ ฅ์€ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ํž˜๋“ค๊ฒŒ ํ•œ๋‹ค. ์ˆจ์€ ์ž…์ถœ๋ ฅ์˜ ์œ ํ˜•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ถ€์ž‘์šฉ: ๋ถ€์ž‘์šฉ์€ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ํฌ์‹œ๋˜์ง€ ์•Š๋Š” ์ถœ๋ ฅ์ด๋ฉฐ, ๋”ฐ๋ผ์„œ ์ˆจ์–ด์žˆ๋‹ค.
  • ์˜ˆ์™ธ: ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋ฉด, ํ”„๋กœ๊ทธ๋žจ ํ๋ฆ„์— ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ์„ค์ •๋œ ๊ณ„์•ฝ์„ ์šฐํšŒํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ ๋‹ค.
  • ๋‚ด์™ธ๋ถ€ ์ƒํƒœ์— ๋Œ€ํ•œ ์ฐธ์กฐ: DateTime.Now์™€ ๊ฐ™์ด ์ •์  ์†์„ฑ์„ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์งˆ์˜ํ•  ์ˆ˜ ์žˆ๊ณ , ๋น„๊ณต๊ฐœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ๋ชจ๋‘ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ์—†๋Š” ์‹คํ–‰ ํ๋ฆ„์— ๋Œ€ํ•œ ์ž…๋ ฅ์ด๋ฉฐ, ๋”ฐ๋ผ์„œ ์ˆจ์–ด์žˆ๋‹ค.

๋ฉ”์„œ๋“œ๊ฐ€ ์ˆ˜ํ•™์  ํ•จ์ˆ˜์ธ์ง€ ํŒ๋ณ„ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ํ”„๋กœ๊ทธ๋žจ์˜ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ•ด๋‹น ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์„ ์ฐธ์กฐ ํˆฌ๋ช…์„ฑ์ด๋ผ๊ณ  ํ•œ๋‹ค.

public int Increment(int x) {
return x + 1;
}

์ด ๋ฉ”์„œ๋“œ๋Š” ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋‹ค. ๋‹ค์Œ ๋‘ ๊ตฌ๋ฌธ์€ ์„œ๋กœ ๋™์ผํ•˜๋‹ค.

int y = Increment(4);
int y = 5;

๋ฐ˜๋ฉด์— ๋‹ค์Œ ๋ฉ”์„œ๋“œ๋Š” ์ˆ˜ํ•™์  ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’์ด ๋ฉ”์„œ๋“œ์˜ ์ถœ๋ ฅ์„ ๋ชจ๋‘ ๋‚˜ํƒ€๋‚ด์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†๋‹ค.

int x = 0;
public int Increment() {
x++;
return x;
}

๐ŸŽˆ ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜๋ž€?โ€‹

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋ชฉํ‘œ๋Š” ๋ถ€์ž‘์šฉ์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ์™€ ๋ถ€์ž‘์šฉ์„ ์ผ์œผํ‚ค๋Š” ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋‘ ๊ฐ€์ง€ ์ฑ…์ž„์€ ๊ฐ๊ฐ๋งŒ ๋ณด๋”๋ผ๋„ ์ถฉ๋ถ„ํžˆ ๋ณต์žกํ•˜๋‹ค. ๋ชจ๋‘ ๊ณ ๋ คํ•˜๋ฉด ๋ณต์žก๋„๊ฐ€ ๋ฐฐ๊ฐ€๋˜๊ณ  ์žฅ๊ธฐ์ ์œผ๋กœ ์ฝ”๋“œ์˜ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์„ ๋ฐฉํ•ดํ•œ๋‹ค. ๋ถ€์ž‘์šฉ์„ ๋น„์ฆˆ๋‹ˆ์Šค ์—ฐ์‚ฐ ๋์œผ๋กœ ๋ชฐ์•„์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ€์ž‘์šฉ๊ณผ ๋ถ„๋ฆฌํ•œ๋‹ค.

๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ฝ”๋“œ ์œ ํ˜•์„ ๊ตฌ๋ถ„ํ•ด์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ€์ž‘์šฉ์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๋Š” ์ฝ”๋“œ: ์ด ์ฝ”๋“œ๋Š” ๋ถ€์ž‘์šฉ์ด ํ•„์š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜ํ•™์  ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•ด๋‹น ๊ฒฐ์ •์— ๋”ฐ๋ผ ์ž‘์šฉํ•˜๋Š” ์ฝ”๋“œ: ์ด ์ฝ”๋“œ๋Š” ์ˆ˜ํ•™์  ํ•จ์ˆ˜์— ์˜ํ•ด ์ด๋ค„์ง„ ๋ชจ๋“  ๊ฒฐ์ •์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ณ€๊ฒฝ์ด๋‚˜ ๋ฉ”์‹œ์ง€ ๋ฒ„์Šค๋กœ ์ „์†ก๋œ ๋ฉ”์‹œ์ง€์™€ ๊ฐ™์ด ๊ฐ€์‹œ์ ์ธ ๋ถ€๋ถ„์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

๊ฒฐ์ •์˜ ๋‚ด๋ฆฌ๋Š” ์ฝ”๋“œ๋Š” ์ข…์ข… ํ•จ์ˆ˜ํ˜• ์ฝ”์–ด๋ผ๊ณ ๋„ ํ•œ๋‹ค. ํ•ด๋‹น ๊ฒฐ์ •์— ๋”ฐ๋ผ ์ž‘์šฉํ•˜๋Š” ์ฝ”๋“œ๋Š” ๊ฐ€๋ณ€ ์…€์ด๋‹ค.

  • ๊ฐ€๋ณ€ ์…ธ์€ ๋ชจ๋“  ์ž…๋ ฅ์„ ์ˆ˜์ง‘ํ•œ๋‹ค.
  • ํ•จ์ˆ˜ํ˜• ์ฝ”์–ด๋Š” ๊ฒฐ์ •์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ์…ธ์€ ๊ฒฐ์ •์„ ๋ถ€์ž‘์šฉ์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

์ด ๋‘ ๊ณ„์ธต์„ ๊ณ„์† ์ž˜ ๋ถ„๋ฆฌํ•˜๋ ค๋ฉด, ๊ฐ€๋ณ€ ์…ธ์˜ ์˜์‚ฌ ๊ฒฐ์ •์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ฒŒ๋” ๊ฒฐ์ •์„ ๋‚˜ํƒ€๋‚ด๋Š” ํด๋ž˜์Šค์— ์ •๋ณด๊ฐ€ ์ถฉ๋ถ„ํžˆ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ๋‹ค์‹œ ๋งํ•ด, ๊ฐ€๋ณ€ ์…ธ์€ ๊ฐ€๋Šฅํ•œ ํ•œ ์•„๋ฌด๋ง๋„ ํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. ๋ชฉํ‘œ๋Š” ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋กœ ํ•จ์ˆ˜ํ˜• ์ฝ”์–ด๋ฅผ ๋‘๋ฃจ ๋‘๋ฃจ๊ณ  ๊ฐ€๋ณ€ ์…ธ์„ ํ›จ์”ฌ ๋” ์ ์€ ์ˆ˜์˜ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์— ๋งก๊ธฐ๋Š” ๊ฒƒ์ด๋‹ค.

๐ŸŽˆ ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜์™€ ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜ ๋น„๊ตโ€‹

ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜์™€ ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜๋Š” ๋น„์Šทํ•œ ์ ์ด ๋งŽ๋‹ค. ๋‘˜ ๋‹ค ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋ผ๋Š” ์•„์ด๋””์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ถ„๋ฆฌ๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๊ตฌ์ฒด์ ์ธ ๋‚ด์šฉ์€ ๋‹ค์–‘ํ•˜๋‹ค.

์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜๋Š” ๋„๋ฉ”์ธ ๊ณ„์ธต๊ณผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋น„์Šค ๊ณ„์ธต์„ ๊ตฌ๋ณ„ํ•œ๋‹ค. ๋„๋ฉ”์ธ ๊ณ„์ธต์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ฑ…์ž„์ด ์žˆ๋Š” ๋ฐ˜๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋น„์Šค ๊ณ„์ธต์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ SMTP ์„œ๋น„์Šค์™€ ๊ฐ™์ด ์™ธ๋ถ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ์˜ ํ†ต์‹ ์— ์ฑ…์ž„์ด ์žˆ๋‹ค. ์ด๋Š” ๊ฒฐ์ •๊ณผ ์‹คํ–‰์„ ๋ถ„๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜๋‹ค.

๋˜ ๋‹ค๋ฅธ ์œ ์‚ฌ์ ์€ ์˜์กด์„ฑ ๊ฐ„์˜ ๋‹จ๋ฐฉํ–ฅ ํ๋ฆ„์ด๋‹ค. ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜์—์„œ ๋„๋ฉ”์ธ ๊ณ„์ธต ๋‚ด ํด๋ž˜์Šค๋Š” ์„œ๋กœ์—๊ฒŒ๋งŒ ์˜์กดํ•ด์•ผ ํ•œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋น„์Šค ๊ณ„์ธต์˜ ํด๋ž˜์Šค์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜์˜ ๋ถˆ๋ณ€ ์ฝ”์–ด๋Š” ๊ฐ€๋ณ€ ์…ธ์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ž๊ธ‰ํ•  ์ˆ˜ ์žˆ๊ณ  ์™ธ๋ถ€ ๊ณ„์ธต๊ณผ ๊ฒฉ๋ฆฌ๋ผ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋กœ ์ธํ•ด ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฝ๋‹ค.

์ด ๋‘˜์˜ ์ฐจ์ด์ ์€ ๋ถ€์ž‘์šฉ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ์— ์žˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜๋Š” ๋ชจ๋“  ๋ถ€์ž‘์šฉ์„ ๋ถˆ๋ณ€ ์ฝ”์–ด์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ์—ฐ์‚ฐ ๊ฐ€์žฅ์ž๋ฆฌ๋กœ ๋ฐ€์–ด๋‚ธ๋‹ค. ์ด ๊ฐ€์žฅ์ž๋ฆฌ๋Š” ๊ฐ€๋ณ€ ์…ธ์ด ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋ฐ˜๋ฉด ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜๋Š” ๋„๋ฉ”์ธ ๊ณ„์ธต์— ์ œํ•œํ•˜๋Š” ํ•œ, ๋„๋ฉ”์ธ ๊ณ„์ธต์œผ๋กœ ์ธํ•œ ๋ถ€์ž‘์šฉ๋„ ๋ฌธ์ œ์—†๋‹ค. ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜์˜ ๋ชจ๋“  ์ˆ˜์ • ์‚ฌํ•ญ์€ ๋„๋ฉ”์ธ ๊ณ„์ธต ๋‚ด์— ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ๊ณ„์ธต์˜ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.

๐Ÿฅ• ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜์™€ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋กœ์˜ ์ „ํ™˜โ€‹

์ƒํƒœ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์™€ ํ†ต์‹  ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ถœ๋ ฅ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ์Šคํƒ€์ผ๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•  ๊ฒƒ์ด๋‹ค.

๐ŸŽˆ ๊ฐ์‚ฌ ์‹œ์Šคํ…œ ์†Œ๊ฐœโ€‹

์ƒ˜ํ”Œ ํ”„๋กœ์ ํŠธ๋Š” ์กฐ์ง์˜ ๋ชจ๋“  ๋ฐฉ๋ฌธ์ž๋ฅผ ์ถ”์ ํ•˜๋Š” ๊ฐ์‚ฌ ์‹œ์Šคํ…œ์ด๋‹ค. ์ด ์‹œ์Šคํ…œ์€ ๊ฐ€์žฅ ์ตœ๊ทผ ํŒŒ์ผ์˜ ๋งˆ์ง€๋ง‰ ์ค„์— ๋ฐฉ๋ฌธ์ž์˜ ์ด๋ฆ„๊ณผ ๋ฐฉ๋ฌธ ์‹œ๊ฐ„์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ํŒŒ์ผ๋‹น ์ตœ๋Œ€ ํ•ญ๋ชฉ ์ˆ˜์— ๋„๋‹ฌํ•˜๋ฉด ์ธ๋ฑ์Šค๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ ์ƒˆ ํŒŒ์ผ์„ ์ž‘์„ฑํ•œ๋‹ค.

๊ฐ์‚ฌ ์‹œ์Šคํ…œ์˜ ์ดˆ๊ธฐ ๊ตฌํ˜„
public class AuditManager {
private readonly int _maxEntriesPerFile;
private readonly string _directoryName;

public AuditManager(int maxEntriesPerFile, string directoryName) { // ์ตœ๋Œ€ ํ•ญ๋ชฉ ์ˆ˜์™€ ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ค์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.
_maxEntriesPerFile = max EntriesPerFile;
_directoryName = directoryName;
}

public void AddRecord(string visitorName, DateTime timeOfVisit) {
// ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ์ „์ฒด ํŒŒ์ผ ๋ชฉ๋ก์„ ๊ฒ€์ƒ‰
string[] filePaths = Directory.GetFiles(_directoryName);
// ์ธ๋ฑ์Šค๋ณ„๋กœ ์ •๋ ฌ
(int index, string path)[] sorted = SortByIndex(filePaths);

string newRecord = visitorName + ';' + timeOfVisit;

// ์•„์ง ๊ฐ์‹œ ํŒŒ์ผ์ด ์—†์œผ๋ฉด ๋‹จ์ผ ๋ ˆ์ฝ”๋“œ๋กœ ์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.
if (sorted.Length == 0) {
string newFile = Path.Combine(_directoryName, "audit+1.txt");
File.WriteAllText(newFile, newRecord);
return;
}

// ๊ฐ์‹œ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ์ตœ์‹  ํŒŒ์ผ์„ ๊ฐ€์ ธ์™€์„œ ํŒŒ์ผ์˜ ํ•ญ๋ชฉ ์ˆ˜๊ฐ€ ํ•œ๊ณ„์— ๋„๋‹ฌํ–ˆ๋Š”์ง€์— ๋”ฐ๋ผ ์ƒˆ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ƒˆ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.
(int currentFileIndex, string currentFilePath) = sorted.Last();
List<string> lines = File.ReadAllLines(currentFilePath).ToList();

if (lines.Count < _maxEntriesPerFile) {
lines.Add(newRecord);
string newContent = string.Join("\r\n", lines);
File.WriteAllText(currentFilePath, newContent);
} else {
int newIndex = currentFileIndex + 1;
string newName = $"audit_{newIndex}.txt";
string newFile = Path.Combine(_directoryName, newName);
File.WriteAllText(newFile, newRecord);
}
}
}

AuditManager ํด๋ž˜์Šค๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ๊ณผ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋ผ ์žˆ์–ด ๊ทธ๋Œ€๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค. ํ…Œ์ŠคํŠธ ์ „์— ํŒŒ์ผ์„ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๋ฉด ํ•ด๋‹น ํŒŒ์ผ์„ ์ฝ๊ณ  ๋‚ด์šฉ์„ ํ™•์ธํ•œ ํ›„ ์‚ญ์ œํ•ด์•ผ ํ•œ๋‹ค.

๋ณ‘๋ชฉ ์ง€์ ์€ ํŒŒ์ผ ์‹œ์Šคํ…œ์ด๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰ ํ๋ฆ„์„ ๋ฐฉํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต์œ  ์˜์กด์„ฑ์ด๋‹ค.
๋˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์€ ํ…Œ์ŠคํŠธ๋ฅผ ๋Š๋ฆฌ๊ฒŒ ํ•œ๋‹ค. ๋กœ์ปฌ ์‹œ์Šคํ…œ๊ณผ ๋นŒ๋“œ ์„œ๋ฒ„ ๋ชจ๋‘ ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์žˆ๊ณ  ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ๋„ ์ €ํ•˜๋œ๋‹ค.

ํ•œํŽธ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ง์ ‘ ์ž‘๋™ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ์ •์˜์— ๋งž์ง€ ์•Š๋Š”๋‹ค. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ๋‘ ๋ฒˆ์งธ์™€ ์„ธ ๋ฒˆ์งธ ํŠน์„ฑ์„ ์ค€์ˆ˜ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ๋ฒ”์ฃผ์— ์†ํ•œ๋‹ค.

  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ๋™์ž‘์„ ๊ฒ€์ฆํ•˜๊ณ 
  • ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•˜๊ณ 
  • ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์™€ ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

๐ŸŽˆ ํ…Œ์ŠคํŠธ๋ฅผ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ ์‚ฌ์šฉโ€‹

ํ…Œ์ŠคํŠธ๊ฐ€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ฒฐํ•จ๋œ ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๋ชฉ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด ํ•ด๊ฒฐํ•œ๋‹ค. ํŒŒ์ผ์˜ ๋ชจ๋“  ์—ฐ์‚ฐ์„ ๋ณ„๋„์˜ ํด๋ž˜์Šค(IFileSystem)๋กœ ๋„์ถœํ•˜๊ณ  AuditManager์— ์ƒ์„ฑ์ž๋กœ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ…Œ์ŠคํŠธ๋Š” ์ด ํด๋ž˜์Šค๋ฅผ ๋ชฉ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฐ์‚ฌ ์‹œ์Šคํ…œ์ด ํŒŒ์ผ์— ์ˆ˜ํ–‰ํ•˜๋Š” ์“ฐ๊ธฐ๋ฅผ ์บก์ฒ˜ํ•œ๋‹ค.

์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋ช…์‹œ์  ์ฃผ์ž…
public class AuditManager {
private readonly int _maxEntriesPerFile;
private readonly string _directoryName;
private readonly IFileSystem _fileSystem;

public AuditManager(
int maxEntriesPerFile, string directoryName, IFileSystem fileSystem
) {
_maxEntriesPerFile = maxEntriesPerFile;
_directoryName = directoryName;
_fileSystem = fileSystem;
}
}

๋‹ค์Œ์€ AddRecord ๋ฉ”์„œ๋“œ๋‹ค.

์ƒˆ๋กœ์šด IFileSystem ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ
  public void AddRecord(string visitorName, DateTime timeOfVisit) {
string[] filePaths = _fileSystem.GetFiles(_directoryName);
(int index, string path)[] sorted = SortByIndex(filePaths);

string newRecord = visitorName + ';' + timeOfVisit;

if (sorted.Length == 0) {
string newFile = Path.Combine(_directoryName, "audit+1.txt");
_fileSystem.WriteAllText(newFile, newRecord);
return;
}

(int currentFileIndex, string currentFilePath) = sorted.Last();
List<string> lines = _fileSystem.ReadAllLines(currentFilePath).ToList();

if (lines.Count < _maxEntriesPerFile) {
lines.Add(newRecord);
string newContent = string.Join("\r\n", lines);
_fileSystem.WriteAllText(currentFilePath, newContent);
} else {
int newIndex = currentFileIndex + 1;
string newName = $"audit_{newIndex}.txt";
string newFile = Path.Combine(_directoryName, newName);
_fileSystem.WriteAllText(newFile, newRecord);
}
}

์ด์ œ AuditManager๊ฐ€ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ๋ถ„๋ฆฌ๋˜๋ฏ€๋กœ, ๊ณต์œ  ์˜์กด์„ฑ์ด ์‚ฌ๋ผ์ง€๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์€ ๊ทธ๋Ÿฌํ•œ ํ…Œ์ŠคํŠธ๋‹ค.

๋ชฉ์„ ์ด์šฉํ•œ ๊ฐ์‚ฌ ์‹œ์Šคํ…œ์˜ ๋™์ž‘ ํ™•์ธ
[Fact]
public void A_new_file_is_created_when_the_current_file_overflows() {
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock
.Setup(x => x.GetFiles("audits"))
.Returns(new string[] {
@"audits\audit_1.txt",
@"audits\audit_2.txt"
});
fileSystemMock
.Setup(x => x.ReadAllLines(@"audits\audit_2.txt"))
.Returns(new List<string> {
"Peter; 2019-04-06T16:30:00",
"Jane; 2019-04-06T16:40:00",
"Jack; 2019-04-06T17:00:00",
});

var sut = new AuditManager(3, "audits", fileSystemMock.Object);

sut.AddRecord("Alice", DateTime.Pars("2019-04-06T18:00:00"));

fileSystemMock.verify(x => x.WriteAllText(
@"audits\audit_3.txt"
"Alice; 2019-04-06T18:00:00",
));
}

์ด ๊ตฌํ˜„์€ ์ดˆ๊ธฐ ๋ฒ„์ „๋ณด๋‹ค ๊ฐœ์„ ๋๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ๋” ์ด์ƒ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋” ๋นจ๋ฆฌ ์‹คํ–‰๋œ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๋ ค๊ณ  ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๋‹ค๋ฃฐ ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์œ ์ง€๋น„๋„ ์ ˆ๊ฐ๋œ๋‹ค. ๋ฆฌํŒฉํ„ฐ๋ง์„ ํ•ด๋„ ํšŒ๊ท€ ๋ฐฉ์ง€์™€ ๋ฆฌํŒฉํ„ฐ๋ง ๋‚ด์„ฑ์ด ๋‚˜๋น ์ง€์ง€ ์•Š์•˜๋‹ค.
ํ•˜์ง€๋งŒ ๋” ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ตœ์„ ์„ ๋‹คํ•ด ๋„์›€์„ ์ฃผ์ง€๋งŒ, ์ž‘์„ฑ๋œ ํ…Œ์ŠคํŠธ๋Š” ์—ฌ์ „ํžˆ ํ‰์ดํ•œ ์ž…์ถœ๋ ฅ์— ์˜์กดํ•˜๋Š” ํ…Œ์ŠคํŠธ๋งŒํผ ์ฝ๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค.

๐ŸŽˆ ํ•จ์ˆ˜ํ˜• ์•„ํ‚คํ…์ฒ˜๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ธฐโ€‹

์ธํ„ฐํŽ˜์ด์Šค ๋’ค๋กœ ๋ถ€์ž‘์šฉ์„ ์ˆจ๊ธฐ๊ณ  ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ AuditManager์— ์ฃผ์ž…ํ•˜๋Š” ๋Œ€์‹ , ๋ถ€์ž‘์šฉ์„ ํด๋ž˜์Šค ์™ธ๋ถ€๋กœ ์™„์ „ํžˆ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด AuditManager๋Š” ํŒŒ์ผ์— ์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ๋‘˜๋Ÿฌ์‹ผ ๊ฒฐ์ •๋งŒ ์ฑ…์ž„์ง€๊ฒŒ ๋œ๋‹ค. ์ƒˆ๋กœ์šด ํด๋ž˜์Šค์ธ Persister๋Š” ๊ทธ ๊ฒฐ์ •์— ๋”ฐ๋ผ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์—…๋ฐ์ดํŠธ๋ฅผ ์ ์šฉํ•œ๋‹ค.