π Chapter 2: λꡬ λ€λ£¨κΈ°
π ν μ€ν νλ μμν¬β
λ€μμ μΉκ° κ°μ²΄, νκ³΅νΈ κ°μ²΄λ₯Ό μ
λ ₯λ°μ createReservation
μ passengerInformation
νλ‘νΌν°κ° μΉκ° κ°μ²΄, flightInformation
νλ‘νΌν°κ° νκ³΅νΈ κ°μ²΄μΈ μλ‘μ΄ κ°μ²΄λ₯Ό λ°ννλ€.
function createReservation(passenger, flight) {
return {
passengerInfo: passenger,
flightInfo: flight,
};
}
ν κ·μ μ λ¨μ ν μ€νΈ μμ΄(λ¨μ ν μ€νΈλ₯Ό κ±°μΉμ§ μκ³ ) μ ν μ½λλ₯Ό 체ν¬μΈ(CVS, SVNκ³Ό κ°μ μμ€ κ΄λ¦¬ μλ²μ μμ μ΄ μμ±ν μ½λλ₯Ό λ°μνλ κ²)ν μλ μμΌλ―λ‘ λ¨μ ν μ€νΈ μμ±μ λ°λμ νμνλ€.
describe('createReservation(passenger, flight)', function() {
it('μ£Όμ΄μ§ passengerλ₯Ό passengerInfo νλ‘νΌν°μ ν λΉνλ€', function() {
var testPassenger = {
firstName: 'μ€μ§',
lastName: 'κΉ',
};
var testFlight = {
number: '3443',
carrier: 'λνν곡',
destination: 'μΈμ°,'
};
var reservation = createReservation(testPassenger, testFlight);
expect(reservation.passengerInfo).toBe(testPassenger);
});
it('μ£Όμ΄μ§ flightλ₯Ό flightInfo νλ‘νΌν°μ ν λΉνλ€', function() {
var testPassenger = {
firstName: 'μ€μ§',
lastName: 'κΉ',
};
var testFlight = {
number: '3443',
carrier: 'λνν곡',
destination: 'μΈμ°,'
};
var reservation = createReservation(testPassenger, testFlight);
expect(reservation.flightInfo).toBe(testFlight);
});
});
it
ν¨μ κ°μλ κ°λ³ λ¨μ ν
μ€νΈκ³ (μ΄ μμμλ 2κ°μ λ¨μ ν
μ€νΈκ° μλ€), μ΄λ€μ ν¨μμμ λ°νλ κ°μ²΄μ μμ±μ΄ μ μ νμ§ expect
ν¨μλ‘ κ²μ¬νλ€.
κ·Έλ°λ° λ¨μ ν
μ€νΈμ μ€λ₯κ° λ³΄μΈλ€. λ°νλ μμ½ κ°μ²΄μ μμ±λͺ
μ passengerInformation
κ³Ό flightInformation
μ΄λΌκ³ λͺ
μΈμ λμ μλλ°, createReservation
κ°λ°μ λ무 μλλ₯Έ λλ¨Έμ§ μμ±λͺ
μ passengerInfo
μ flightInfo
λ‘ μλͺ» μ½λ©ν κ²μ΄λ€.
λͺ μΈκ° μλλΌ ν¨μ μ½λμ κ°λ°μ λ°λΌ ν μ€νΈλ₯Ό μμ±ν νμ ν μ€νΈλ κΈ°λνλ ν¨μ μλμ΄ μλ, ꡬνλ ν¨μμ (μλͺ»λ) μ€μ μλμ νμΈν κΌ΄μ΄λ€. λͺ μΈ κΈ°μ€μΌλ‘ ν μ€νΈ μ½λλ₯Ό μμ±νμΌλ©΄ μ λΉμ΄ μμ±λͺ μ ν릴 μΌμ μμμ κ²μ΄λ€.
π μλͺ»λ μ½λ λ°κ²¬νκΈ°β
TDDλ μ½λ κ²°ν¨μ μ΅λν 빨리, 곧 μ½λ μμ± μ§ν κ°μ§νλ©°, μμ κΈ°λ₯ νλλΌλ ν μ€νΈλ₯Ό λ¨Όμ μμ±ν λ€, μ΅μνμ μ½λλ§μΌλ‘ κΈ°λ₯μ ꡬννλ€.
λ€μ createReservation
ν¨μλ‘ λ€μ λμκ° ν
μ€νΈλ₯Ό λ¨Όμ μμ±νλ©΄ μ΄λ»κ² λ¬λΌμ§λ μμ보μ. λ€μ λ§νμ§λ§, μ΄ ν¨μμ λͺ
μΈλ λ€μκ³Ό κ°λ€.
createReservation
μ μΉκ° κ°μ²΄, νκ³΅νΈ κ°μ²΄λ₯Ό μ λ ₯λ°μpassengerInformation
νλ‘νΌν°κ° μΉκ° κ°μ²΄,flightInformation
νλ‘νΌν°κ° νκ³΅νΈ κ°μ²΄μΈ μλ‘μ΄ κ°μ²΄λ₯Ό λ°ννλ€.
λ¨Όμ passengerInformation
νλ‘νΌν° ν λΉμ΄ μ μμ μΈμ§ νμΈνλ ν
μ€νΈλ₯Ό μμ±νλ€.
describe('createReservation(passenger, flight)', function() {
it('μ£Όμ΄μ§ passengerλ₯Ό passengerInformation νλ‘νΌν°μ ν λΉνλ€', function() {
var testPassenger = {
firstName: 'μ€μ§',
lastName: 'κΉ',
};
var testFlight = {
number: '3443',
carrier: 'λνν곡',
destination: 'μΈμ°,'
};
var reservation = createReservation(testPassenger, testFlight);
expect(reservation.passengerInformation).toBe(testPassenger);
});
});
κ·Έλ° λ€μμ μ΄ ν
μ€νΈλ₯Ό μ±κ³΅μν¬ createReservation
μ½λλ₯Ό μ΅μνμΌλ‘ μμ±νλ€.
function createReservation(passenger, flight) {
return {
passengerInfo: passenger,
flightInformation: flight,
};
}
λ¨μ ν
μ€νΈνλ©΄ μ€ν¨νλ€. μ΄μ κ° λκΉ? λ°ν κ°μ²΄μ μμ±λͺ
μ μλͺ»ν΄μ passengerInformation
λμ passengerInfo
λ‘ μ μλ€. μμ±λͺ
μ μ μ νκ³ λ€μ ν
μ€νΈνλ©΄ μ±κ³΅νλ€.
λ°ν κ°μ²΄μ μμ±λͺ
μ μλͺ» μ΄ μ€μκ° createReservation
ν¨μλ₯Ό ꡬνν μ½λμ μ λ³΅ν΄ μμ§λ§, μ΄λ²μλ ν
μ€νΈλ₯Ό λ¨Όμ μμ±ν λ€ λͺ
μΈμ λ°λΌ ν
μ€νΈλ₯Ό νμΌλ―λ‘ λ€λ₯Έ κ°λ°μκ° ν΅ν© ν
μ€νΈλ₯Ό μ§ννλ€κ° μ°λ½ν λκΉμ§ λͺ μκ° κΈ°λ€λ¦¬μ§ μκ³ λ μλ¬λ₯Ό μ¦μ νμΈνμ¬ μ‘°μΉν μ μλ€.
π ν μ€νΈμ±μ κ°μνμ¬ μ€κ³νκΈ°β
ν μ€νΈλ₯Ό λ¨Όμ μμ±νλ 건 μ½λμ ν μ€νΈμ±μ μ°¨νμ λκ³ λ³Ό λ¬Έμ κ° μλλΌ μ°μ μ μΈ μ£Όμ κ΄ μ¬μ¬λ‘ μκ°νλ κ²μ΄λ€. ν μ€νΈνκΈ° μ¬μ΄ μ½λκ° μ μ§ λ³΄μμ±κ³Ό νμ₯μ±μ΄ μλ±ν μ°μνλ€. ν μ€νΈμ±μ μ€κ³ λͺ©νλ‘ μ νλ©΄ SOLIDν μ½λλ₯Ό μμ±ν μ μλ€.
TDDμ μΆ©μ€ν μ¬λμ΄λ©΄ 무쑰건 μ μ§ν΄μ createReservation
μ κ³ μΉκΈ°λ³΄λ€λ μΌλ¨ μ κΈ°λ₯μ νμΈνλ ν
μ€νΈλ₯Ό μμ±νλ€. 첫 λ²μ§Έ ν
μ€νΈμμλ μμ½ λ°μ΄ν°κ° μ λλ‘ μΉ μλΉμ€ μ’
λ¨μ κΉμ§ 보λ΄μ‘λμ§λ₯Ό νμΈνλ€.
κ·Έλ°λ° μ¬κΈ°μ createReservation
μ΄ μΉ μλΉμ€ ν΅μ κΉμ§ 맑μμΌ νλ? νλ μλ¬Έμ νλ 건 μκΈ° κ³λ°μ μλΉν λμμ΄ λλ€.
describe('createReservation(passenger, flight)', () => {
// Existing tests
it('μμ½ μ 보λ₯Ό μΉ μλΉμ€ μ’
λ¨μ μΌλ‘ μ μ‘νλ€', () => {
// createReservationμ΄ μΉ μλΉμ€ ν΅μ κΉμ§ 맑μμΌ νλ?
});
});
μ λ΅μ κ·Έλ΄ μΌμ μλ€. μΉ μλΉμ€ ν΅μ μ λ΄ κ°μ²΄κ° μμΌλ©΄ νλ λ§λλ νΈμ΄ μ’λ€. μ½λ ν μ€νΈμ±μ κ·Ήλννλ©΄ SOLID μμΉμ μ΄κΈ΄ μ½λλ₯Ό μ½κ² μμλΌ μ μλ€.
π κΌ νμν μ½λλ§ μμ±νκΈ°β
TDD μμ μ μ°¨λ μμ κΈ°λ₯ νλλ₯Ό κ²μ¦νλ €λ©΄ μ€ν¨νλ ν μ€νΈλ₯Ό λ¨Όμ μμ±ν λ€, ν μ€νΈλ₯Ό μ±κ³΅μν¬ λ§νΌλ§ μ΅μνμΌλ‘ μ½λ©νλ€. κ·Έ ν λ΄λΆμ μΌλ‘ ꡬν μΈλΆλ₯Ό λ³κ²½νλ 리ν©ν λ§ κ³Όμ μ κ±°μ³ κ°λ° μ€μΈ μ½λμμ μ€λ³΅ μ½λλ₯Ό λ€μ΄λΈλ€.
μ΅μνμ μ½λλ₯Ό λ£μ λ€μ 리ν©ν λ§μΌλ‘ μ€λ³΅ μ½λλ₯Ό μμ κ³ ,... μ΄λ° κ³Όμ μ κ±°μΉλ©΄μ κ²°κ΅ λ§μ§λ§μλ κΌ νμν μ½λλ§ μ΄μλ¨κ² λλ€.
π μμ ν μ μ§ λ³΄μμ 리ν©ν°λ§β
TDDλ₯Ό μ€μ²νλ©΄ νλ‘μ νΈ μ ν μ½λλ₯Ό λμμΌλ‘ νμ€ν λ¨μ ν μ€νΈ κΎΈλ¬λ―Έλ₯Ό ꡬμΆν μ μλ€. μμ μ μ λμκ°λ μ½λκ° μ§κΈμ μ λλ‘ μλνμ§ μλ νκ· κ²°ν¨μ μ½λ νμ§κ³Ό λ―Ώμμ±μ λ¨μ΄λ¨λ¦¬λ μμΈμ΄λ€.
λ¨μ ν μ€νΈμ κ²½μ° ν μ€νΈ κΎΈλ¬λ―Έλ₯Ό κ°λ°/보μνλλΌ μ¬λ° λΉ μ©μ΄ λ€μ΄κ°λλ°, 보νκ³Ό λ§μ°¬κ°μ§λ‘ μ΄ μ¬λ° λΉμ©μ μ§λΆνλ λΆλ΄μμ λ²μ΄λλ μμ μ΄ μ¨λ€.
μ’ ν©μ μΈ λ¨μ ν μ€νΈ κΎΈλ¬λ―Έκ° λ§λ ¨λ μ ν μ½λλ₯Ό νμ₯ λλ 보μν λλ λΉμ·ν μλκ°μ λλ μ μλ€. μ€μλ‘ λ€λ₯Έ μ½λλ₯Ό 건λλ¦¬μ§ μμλ°λ νμ μ νκ³ μ½λ μΌλΆλ₯Ό λ³κ²½ν μ μκΈ° λλ¬Έμ΄λ€.
π μ€ν κ°λ₯ν λͺ μΈβ
TDD μ€μ² κ²°κ³Ό, νννκ² κ΅¬μΆλ λ¨μ ν μ€νΈ κΎΈλ¬λ―Έλ ν μ€νΈ λμ μ½λμ μ€ν κ°λ₯ν λͺ μΈ μν λ νλ€.
createReservation
ν¨μλ‘ μλ₯Ό λ€λ©΄, λ¨μ ν
μ€νΈν κ²°κ³Ό λ©μμ§λ₯Ό λ³΄κ³ μ΄ ν¨μκ° λ¬΄μ¨ μΌμ νλμ§ ν° κ·Έλ¦Όμ κ·Έλ €λ³Ό μ μλ€. createReservation
μ΄ νλ μΌμ κ΅³μ΄ μ½λλ₯Ό μ½κ³ λΆμνμ§ μμλ λ¨μ ν
μ€νΈκ° μ΅λ€ μλ €μ£Όλ μ
μ΄λ€. λ¨μ ν
μ€νΈκ° μ μ¬νλ μ€ν κ°λ₯ λͺ
μΈλ νλ‘μ νΈ μ°Έμ¬ κ°λ°μμκ²λ, κ³Όκ±°μ μμ μ΄ μμ±ν μ½λλ₯Ό λ€μ μ°Ύμ보κ²λ μλ κ°λ°μμκ²λ ν‘ν‘ν νλͺ«νλ€.
π μ¬μ€λ―Ό λ€μ΄κ°κΈ°β
μ¬μ€λ―Όμ νμ μ£Όλ κ°λ°(Behavior-Driven Development, BDD) λ°©μμΌλ‘ μλ°μ€ν¬λ¦½νΈ λ¨μ ν μ€νΈλ₯Ό μμ±νκΈ° μν λΌμ΄λΈλ¬λ¦¬λ€.
λꡬμ λν μμΈν μ€λͺ μ 곡μ ννμ΄μ§λ₯Ό μ°Έμ‘° λ° μ± μ μ°Έκ³ (P.72 ~ P.78)
π μμ‘΄μ± μ£Όμ νλ μμν¬β
π μμ‘΄μ± μ£Όμ μ΄λ?β
μΉνμ μΌλ§ λ¨μ§ μμ μλ°μ€ν¬λ¦½νΈ μ½νΌλ°μ€ νμ¬μ μΉ μ¬μ΄νΈ κ΅¬μΆ μ 무λ₯Ό μμνλ€. μ°Έκ°μ μ’μ μμ½μ νμλ€. μΉνμ μ’μ μμ½ κΈ°λ₯μ κ°μΆ ν΄λΌμ΄μΈνΈ μΈ‘ μ½λ κ°λ°μ 맑μλ€.
DB μ°λμ μ½νΌλ°μ€ μΉ μλΉμ€λ₯Ό νΈμΆνκ² λμ΄ μλ€. κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ° μμΉμ μΆ©μ€ν μΉνμ μ°μ ConferenceWebSvc
κ°μ²΄μ μλΉμ€λ₯Ό μΊ‘μννκ³ λ©μ§ νμ
λ©μμ§λ₯Ό νλ©΄μ νμν μλ°μ€ν¬λ¦½νΈ κ°μ²΄ Messenger
λ₯Ό μμ±νλ€.
μ°Έκ°γ μλ 1μΈλΉ μΈμ μ 10κ°κΉμ§ λ±λ‘ν μ μλ€. μ°Έκ°μκ° ν μΈμ μ λ±λ‘νλ©΄ κ·Έ κ²°κ³Όλ₯Ό μ±κ³΅/μ€ν¨ λ©μμ§λ‘ νλ©΄μ νμνλ ν¨μλ₯Ό κ°λ°ν΄μΌ νλ€. λ€μ μμ λ μ΄κΈ° λ²μ μ΄λ€.
Attendee = function(attendeeId) {
// newλ‘ μμ±νλλ‘ κ°μ νλ€.
if (!(this instanceof Attendee)) {
return new Attendee(attendeeId);
}
this.attendeeId = attendeeId;
this.service = new ConferenceWebSvc();
this.messenger = new Messenger();
};
// μ£Όμ΄μ§ μΈμ
μ μ’μ μμ½μ μλνλ€.
// μ±κ³΅/μ€ν¨ μ¬λΆλ₯Ό λ©μμ§λ‘ μλ €μ€λ€.
Attendee.prototype.reserve = function(sessionId) {
if (this.service.reserve(this.attendeeId, sessionId)) {
this.messenger.success('μ’μ μμ½μ΄ μλ£λμμ΅λλ€!', +
' κ³ κ°λμ' + this.service.getRemainingReservation() +
' μ’μμ μΆκ° μμ½νμ€ μ μμ΅λλ€.');
} else {
this.messenger.failure('μ£μ‘ν©λλ€, ν΄λΉ μ’μμ μμ½νμ€ μ μμ΄λλ€.');
}
};
ConferenceWebSvc
λ΄λΆμλ HTTP νΈμΆμ΄ μλ€. μ΄λ κ² HTTP ν΅μ μ΄ νμν μ½λλ λ¨μ ν
μ€νΈλ₯Ό μ΄λ»κ² ν κΉ? λ¨μ ν
μ€νΈλ κ·Έ μμ²΄λ‘ μ μνκ³ νκ³ ν΄μΌ νλ€. κ·Έλ¦¬κ³ Messenger
λ λ©μμ§λ§λ€ OK λ²νΌμ΄ μμ΄μΌ νλλ°, μ΄ λν μ΄ λͺ¨λμμ λ¨μ ν
μ€νΈν λμμ μλλ€.
Attendee
κ°μ²΄κ° μλλΌ μ΄ κ°μ²΄κ° μμ‘΄νλ μ½λλ€. μμ‘΄μ±μ μ£Όμ
νλ μμΌλ‘ λ°κΎΈλ©΄ ν΄κ²°ν μ μλ€. μ¦, ConferenceWebSvc
μ Messenger
μμ μμ‘΄μ±μ νλ μ½λ±νμ§ λ§κ³ μ΄λ€μ Attendee
μ μ£Όμ
νλ κ²μ΄λ€. λ¨μ ν
μ€νΈμ©μΌλ‘λ λͺ¨μ체(fake)λ μ¬μ€λ―Ό μ€νμ΄ κ°μ λ체μ λ₯Ό μ£Όμ
νλ©΄ λλ€.
// μ΄μ νκ²½:
var attendee = new Attendee(new ConferenceWebSvc(), new Messenger(), id);
// κ°λ°(ν
μ€νΈ) νκ²½:
var attendee = new Attendee(fakeService, fakeMessenger, id);
μ΄μ²λΌ DI νλ μμν¬λ₯Ό μ¬μ©νμ§ μκ³ μμ‘΄μ±μ μ£Όμ
νλ κ²μ λκ³ λΉμμ μμ‘΄μ± μ£Όμ
μ΄λΌ νλ€. λ€μ μμ λ λΉμμ μμ‘΄μ± μ£Όμ
λ°©μμΌλ‘ μμ±ν Attendee
κ°μ²΄λ€.
Attendee = function(service, messenger, attendeeId) {
// newλ‘ μμ±νλλ‘ κ°μ νλ€.
if (!(this instanceof Attendee)) {
return new Attendee(attendeeId);
}
this.attendeeId = attendeeId;
this.service = service;
this.messenger = messenger;
}
π μμ‘΄μ±μ μ£Όμ νμ¬ λ―Ώμμ§ν μ½λ λ§λ€κΈ°β
DIλ μ€μ κ°μ²΄λ³΄λ€ μ£Όμ ν μ€νμ΄λ λͺ¨μ κ°μ²΄μ λ λ§μ μ μ΄κΆμ μ겨주λ―λ‘ λ€μν μλ¬ μ‘°κ±΄κ³Ό κΈ°μ΄ν μν©μ λ§λ€μ΄λ΄κΈ° μ½λ€. νΉμ λͺ¨λ₯Ό λ§μ½μ μ¬νλ₯Ό νλκ² μ»€λ²ν μ μκ² ν μ€νΈλ₯Ό μμ±ν μ μλ€.
λν, DIλ μ½λ μ¬μ¬μ©μ μ κ·Ήμ μΌλ‘ μ λνλ€. μμ‘΄μ±μ νμ, νλ μ½λ©ν λͺ¨λμ λ¬΄κ±°μ΄ μ§μ μ§μ§ λκ³ λ€λλ ν°λΌ λ³΄ν΅ μ¬μ¬μ©νκΈ° μ΄λ ΅λ€.
π μμ‘΄μ± μ£Όμ μ λͺ¨λ κ²β
μμ‘΄μ± μ£Όμ μ μ΄λ ΅μ§ μλ€. λλ¦¬μ΄ μΆμ νΈμνκ² ν΄μ€λ€.
μ΄λ€ κ°μ²΄λ₯Ό μ½λ©νλ μ΄λ€ κ°μ²΄λ₯Ό μμ±νλ μ§ μ€μ€λ‘ λ€μ μ§λ¬Έμ ν΄λΆμ. ν κ°μ§λΌλ λ΅λ²μ΄ μλΌλ©΄ μ§μ μΈμ€ν΄μ€ννμ§ λ§κ³ μ£Όμ νλ λ°©ν₯μΌλ‘ μκ°μ μ ννλΌ.
- κ°μ²΄ λλ μμ‘΄μ± μ€ μ΄λ νλλΌλ DB, μ€μ νμΌ, HTTP, κΈ°ν μΈνλΌ λ±μ μΈλΆ μμμ μμ‘΄νλκ°?
- κ°μ²΄ λ΄λΆμμ λ°μν μ§ λͺ¨λ₯Ό μλ¬λ₯Ό ν μ€νΈμμ κ³ λ €ν΄μΌ νλ?
- νΉμ ν λ°©ν₯μΌλ‘ κ°μ²΄λ₯Ό μλμμΌμΌ ν ν μ€νΈκ° μλκ°?
- μ΄ μλνν° μ 곡 κ°μ²΄κ° μλλΌ μ¨μ ν λ΄κ° μμ ν κ°μ²΄μΈκ°?
π μ¬λ‘ μ°κ΅¬: κ²½λκΈ μμ‘΄μ± μ£Όμ νλ μμν¬ κ°λ°β
μ§κΈκΉμ§λ μμ‘΄μ± μ£Όμ μ νλ μ½λ©νλ€. μ΅μ μ μλλ€. μ λ¬Έκ°λ€μ΄ μμ‘΄μ± μ£Όμ νλ μμν¬λ μ΄λ κ² μλνλ€.
- μ ν리μΌμ΄μ μ΄ μμλμλ§μ κ° μΈμ ν°λΈ(injectable: μ£Όμ κ°λ₯ν, λͺ¨λ μμ‘΄μ±μ μ§ν©μ μΌλ‘ μΌμ»«λ λ§μ΄λ€) λͺ μ νμΈνκ³ ν΄λΉ μΈμ ν°λΈμ΄ μ§λ μμ‘΄μ±μ μ§μΉνλ©° μμλλ‘ DI 컨ν μ΄λμ λ±λ‘νλ€.
- κ°μ²΄κ° νμνλ©΄ 컨ν μ΄λμ μμ²νλ€.
- 컨ν μ΄λλ μΌλ¨ μμ²λ°μ κ°μ²΄μ κ·Έ μμ‘΄μ±μ λͺ¨λ μ¬κ·μ μΌλ‘ μΈμ€ν΄μ€ννλ€. κ·Έλ° λ€μ, μ건μ λ°λΌ νμν κ°μ²΄μ κ°κ° μ£Όμ νλ€.
μ¬κΈ°μ μ€λͺ νλ μμ λ μλ½.. μ± μ μ°Έκ³ (P.81 ~ P.90)
TIPβ
- λμ± νμ€ν λ€κ±°ν°λΈ ν μ€νΈ(negative test)λ₯Ό μν΄μλ μλ¬κ° λ¬λ€λ μ¬μ€λΏλ§ μλλΌ μ€μ μλ¬ λ©μμ§κΉμ§ νμΈνλΌ. νλ‘ν νμ μ΄λ ν¨μλ₯Ό ν΅ν΄ ν μ€νΈ λμμ΄ κ°μ§ λ©μμ§λ₯Ό λ°μΌλ‘ νμΆνλ κ²μ΄λ€.
- μλ¬ μ²λ¦¬ μ½λλ₯Ό μ μΌ λ¨Όμ ν μ€νΈνλΌ. κ·Έλ€μ λ€λ₯Έ μ λ¬΄λ‘ λμ΄κ°λ λ¦μ§ μλ€.
- μ½λκ° μ ν μμ΄λ μ’μΌλ ν μ€νΈλ₯Ό μ±κ³΅μν¬ μ΅μνμ μ½λλ§ μμ±νλΌ. μ ν리μΌμ΄μ μ½λκ° ν μ€νΈλ³΄λ€ μμ λκ°λ©΄ μ λλ€.
- 리ν°λ΄ λμ λ³μλͺ μ μ μ ν΄μ DRYνκ³ μκΈ° μμ μ μΈ ν μ€νΈλ₯Ό μμ±νλΌ.
π μμ‘΄μ± μ£Όμ νλ μμν¬ νμ©β
μμ μλ°μ€ν¬λ¦½νΈ μ½νΌλ°μ€ μ°Έκ°μμ μ’μ μμ½ λͺ¨λμ κ°λ°νλ©΄μ Attendee
μ μμ‘΄μ±μ μμ μ μμ±μμ νλ μ½λ©νμ¬ μ£Όμ
νμλ€.
var attendee = new Attendee(new ConferenceWebSvc(), new Messenger(), id);
μ΄μ μ ν©ν DI 컨ν μ΄λλ₯Ό λ§λ ¨νμΌλ κ°μ²΄λ₯Ό μμ±ν λλ§λ€ μμ‘΄μ±μ νλ μ½λ©ν΄μ λ£μ§ μμλ λλ€.
μ μ κ°μ²΄ MyApp
λ΄λΆμμ μλνλ μ ν리μΌμ΄μ
μ λ€μ μμ μ κ°μ μ€μ μ½λλ₯Ό μκ°ν μ μλ€.
MyApp = {};
MyApp.diContainer = new DiContainer();
MyApp.diContainer.register(
'Service', // μΉ μλΉμ€λ₯Ό κ°λ¦¬ν€λ DI νν¬
[], // μμ‘΄μ± μμ
function() { // μΈμ€ν΄μ€λ₯Ό λ°ννλ ν¨μ
return new ConferenceWebSvc();
},
);
MyApp.diContainer.register(
'Messenger',
[],
function() {
return new Messenger();
},
);
MyApp.diContainer.register(
'AttendeeFactory',
['Service', 'Messenger'], // Attendeeλ service λ° messengerμ μμ‘΄νλ€.
function(service, messenger) {
return function(attendeeId) {
return new Attendee(service, messenger, attendeeId);
}
},
)
Attendee
λ₯Ό μ΄λ»κ² DiContainer
μμ λ£λμ§ μ£Όλͺ©νλΌ. λ§€μ° μ€μν κ³ κΈ κΈ°λ²μ΄λ€. Attendee
λ₯Ό λ§λλ ν¨μκ° μλ, Attendee
λ₯Ό λ§λ€ ν©ν 리λ₯Ό λ§λλ ν¨μκ° λ±λ‘μ λμ νλ€. Attendee
λ μμ μ μμ‘΄μ± μΈμλ attendeeId
νλΌλ―Έν°κ° νμνλ―λ‘ DI 컨ν
μ΄λλ μ΄λ κ² μ½λ©νλ€.
var attendee = MyApp.diContainer.get('Attendee', attendeeId);
νμ§λ§ κ·Έλ¬λ©΄ λ€λ₯Έ κ°μ²΄μ μ¬κ·μ μμ‘΄μ±μΌλ‘ Attendee
λ₯Ό μ 곡ν λ°©λ²μ΄ μλ€.
λ€μ μμ μ²λΌ ν©ν λ¦¬κ° μμΌλ©΄ μ ν리μΌμ΄μ
κΉμν κ³³μμλ DI 컨ν
μ΄λλ‘λΆν° Attendee
λ₯Ό κ°μ Έμ¬ μ μλ€.
var attendeeId = 123;
var sessionId = 1;
// DI 컨ν
μ΄λμμ attendeeIdλ₯Ό λ겨 Attendeeλ₯Ό μΈμ€ν΄μ€ννλ€.
var attendee = MyApp.diContainer.get('AttendeeFactory')(attendeeId);
attendee.reserve(sessionId);
π μ΅μ μμ‘΄μ± μ£Όμ νλ μμν¬β
- μ΅κ·€λ¬ JS
- 리콰μ΄μ΄ JS
π μ μ€ν©νΈ ν΄ν·β
μ μ€ν©νΈ μ§ν₯ νλ‘κ·Έλλ°(AOP)μ (λ¨μΌν μ± μ λ²μ λ΄μ μμ§ μμ) νλ μ΄μμ κ°μ²΄μ μ μ©ν μ½λλ₯Ό νλ° λ¬Άμ΄ λμ λμ§ μκ² κ°μ²΄μ λ°°ν¬νλ κΈ°λ²μ΄λ€.
AOP μ©μ΄λ‘, λ°°ν¬ν μ½λ μ‘°κ°μ μ΄λλ°μ΄μ€(advice), μ΄λλ°μ΄μ€κ° μ²λ¦¬ν λ¬Έμ λ₯Ό μ μ€ν©νΈ(aspect) λλ ν‘λ¨ κ΄μ¬μ¬(cross-cutting concern)λΌκ³ νλ€.
π μ¬λ‘ μ°κ΅¬: AOP μλ/μλ μΊμ±β
- μμ μλ΅. (P.94, 95)
AOPλ‘ λ―Ώμμ§ν μ½λ λ§λ€κΈ°β
AOPλ‘ μ΄λ»κ² νλ©΄ λ―Ώμμ§ν μ½λλ₯Ό λ§λ€κΉ?
- AOPλ ν¨μλ₯Ό λ¨μνκ² μ μ§νλ€. ν¨μ κ°μμ λ¨μΌ μ± μμ μνν λΏμ΄λ€. λ¨μν¨μ 곧 λ―Ώμμ±μ΄λ€.
- AOPλ μ½λλ₯Ό DRYνκ² ν΄μ€λ€. μ΄λ€ μ½λκ° μ¬κΈ°μ κΈ° μΆλͺ°νλ©΄ λμ€μ λ€λ₯Έ κ°λ°μκ° μλͺ» 건λ릴 μ¬μ§λ λ§κ³ , κ·Έλ¬λ€ 보면 λκΈ°νκ° κΊ μ§ κ°λ₯μ±μ΄ λΉμ°ν 컀μ§λ€. κ·Έλ°λ° μ¬κΈ°μ λμΉλ©΄ μ λ ν¬μΈνΈλ, κΈ°μ‘΄ κΈ°λ₯μ μ κΈ°λ₯μ λΆμ΄λ μ½λλ₯Ό λ°λ³΅νκ³ μΆμ§ μλ€λ μ μ΄λ€.
μ¬λ¬ μ½λ λΈλ‘μ μμ²΄λ‘ λ°λ³΅νμ§ μλ μΌλ§νΌ λ€λ₯Έ μ½λμ μ°κ²°νλ λΆλΆμ λ°λ³΅νμ§ μλ μΌλ μ€μνλ€.
- AOPλ μ ν리μΌμ΄μ μ€μ μ ν κ³³μ μ§μ€μν¨λ€. μ μ€ν©νΈ μ€μ μ΄ λ¨μΌ μ± μμΈ ν¨μκ° νλλ§ μμΌλ©΄ λΆμ κΈ°λ₯ μ 체λ₯Ό μ°Ύμ λ μ΄ ν¨μλ§ λ€μ§λ©΄ λλ€. 무μλ³΄λ€ λλ²κΉ ν λ μμ½κ² μΊμ± κ°μ κΈ°λ₯μ λκ±°λ μΈμ μ²΄ν¬ κΈ°λ₯μ μΌ€ μ μμ΄ μ’λ€.
π μ¬λ‘ μ°κ΅¬: Aop.js λͺ¨λ κ°λ°β
μ μ€ν©νΈ νλ‘κ·Έλλ°μ μλ‘μ΄ λ°©λ²μΌλ‘ ν¨μλ₯Ό λμ΄λͺ¨μλ€.
μ°λ¦¬λ νλ λλ¦ μν λ²κ·Έμ λ°μ΄λΈ ν΄λ μ΄ν΄μ΄ κ°λ°ν μμ£Ό μ°μν νλ μμν¬(Aop.jsμμ 무λ£λ‘ λ΄λ €λ°μ μ μλ€)λ λ€μκ³Ό κ°λ€.
// Created by Fredrik Appelberg: http://fredrik.appelberg.me/2010/05/07/aop-js.html
// νλ‘ν νμ
μ μ§μν μ μκ² λ°μ΄λΈ ν΄λ μ΄ν΄μ΄ μμ ν¨
Aop = {
// μ£Όμ΄μ§ μ΄λ¦κ³΅κ°μ 맀μΉλλ λͺ¨λ ν¨μ μ£Όλ³(around)μ μ΄λλ°μ΄μ€λ₯Ό μ μ©νλ€.
around: function(pointcut, advice, namespaces) {
// μ΄λ¦κ³΅κ°μ΄ μμΌλ©΄ μ μ μ΄λ¦κ³΅κ°μ μ°Ύμλ΄λ κΌΌμλ₯Ό μ΄λ€.
if (namespaces == undefined || namespaces.length == 0)
namespaces = [ (function(){return this;}).call() ];
// μ΄λ¦κ³΅κ°μ μ λΆ μννλ€.
for(var i in namespaces) {
var ns = namespaces[i];
for(var member in ns) {
if(typeof ns[member] == 'function' && member.match(pointcut)) {
(function(fn, fnName, ns) {
// member fn μ¬λ‘―μ 'advice' ν¨μλ₯Ό νΈμΆνλ λνΌλ‘ κ΅μ²΄νλ€.
ns[fnName] = function() {
return advice.call(this, { fn: fn,
fnName: fnName,
arguments: arguments });
};
})(ns[member], member, ns);
}
}
}
},
next: function(f) {
return f.fn.apply(this, f.arguments);
}
};
Aop.before = function(pointcut, advice, namespaces) {
Aop.around(pointcut,
function(f) {
advice.apply(this, f.arguments);
return Aop.next.call(this, f);
},
namespaces);
};
Aop.after = function(pointcut, advice, namespaces) {
Aop.around(pointcut,
function(f) {
var ret = Aop.next.call(this, f);
advice.apply(this, f.arguments);
return ret;
},
namespaces);
};
module.exports = Aop;
ν μ€νΈ μ£Όλ κ°λ°μ νλ©΄ κ³Όκ±°μ λ°©λ²λ‘ μ²λΌ λ―Ώμ μκ³ μ°μν μ½λλ₯Ό λ§λ€ μ μλ€.
AOPμ ν΅μ¬μ ν¨μ μ€ν(νκΉ)μ κ°λ‘μ±μ΄ λ€λ₯Έ ν¨μ(μ΄λλ°μ΄μ€)λ₯Ό μ€ννκΈ° μ§μ μ΄λ μ§ν, λλ μ νμ μ€νμν€λ κ²μ΄λ€.
- TDDλ‘ AOPλ₯Ό ꡬννλ μμ μλ΅ (P.97 ~ P.110)
π μ½λ κ²μ¬ λꡬβ
μ½λ κ²μ¬ λꡬλ μ½λλ₯Ό μ€ννμ§ μμ μνμμ μμ€ μ½λμ ꡬ쑰/ꡬ문μ μ‘°μ¬νλ, μ μ λΆμμ μννλ€. μ½λ μ€ν μ μλ¬κ° λ κ±° κ°μ νλ‘κ·Έλλ° μΈμ΄λ₯Ό λΆμ ννκ² μ¬μ©ν κ³³μ μ°Ύμ μλ €μ£Όλ μΌμ΄ μ£Όλ μ 무λ€.
μ΄λ° λꡬλ₯Ό λ³΄ν΅ λ¦°ν°(linter)λΌκ³ νλ€.
π λ¦°ν λκ΅¬λ‘ λ―Ώμμ§ν μ½λ λ§λ€κΈ°β
λ¦°ν μ νΉν μλ°μ€ν¬λ¦½νΈ μ½λ© μ κΈ΄μνλ€. μΈν°νλ¦¬ν° μΈμ΄μΈ μλ°μ€ν¬λ¦½νΈλ κ°λ°μκ° μ€μν΄λ λλΌκ³ μκΈ°ν΄μ£Όλ μ»΄νμΌλ¬κ° μμ΄μ μ½λλ₯Ό μ€νν΄λ³΄κΈ° μ μλ ꡬ문 μλ¬λ₯Ό μ κΈΈμ΄ μλ€.
π λꡬλ€β
- JSHint
- ESLint
π μ격 λͺ¨λβ
νΉμ μ€μ½ν(μ μ λλ ν¨μ μ€μ½ν)μ λ€μ μ½λλ₯Ό λ£μΌλ©΄ μλ°μ€ν¬λ¦½νΈ ν΄μκΈ°λ μ ν λ€λ₯Έ λ°©μμΌλ‘ μ²λ¦¬νλ€.
'use strict';
μ΄ μ§μμκ° μλ μ½λμμ κ°λ°μκ° νν μ μ§λ₯΄λ μ€μλ₯Ό λ²νλ©΄ μλ°μ€ν¬λ¦½νΈ μλ¬κ° λλ€.(μ: λ³μλ₯Ό μ μΈνκΈ°λ μ μ μ¬μ©, μ½κΈ° μ μ© νλ‘νΌν°λ₯Ό μμ , μμ½μ΄λ‘ λ³μλ₯Ό λͺ λͺ λ±).
μ격 λͺ¨λλ₯Ό μ§μνμ§ μλ μλ°μ€ν¬λ¦½νΈ νκ²½μμ μ€ννλ©΄ 'use strict'
λ¬Έμμ΄μ 무μλλ€.
π μ 리νκΈ°β
λ¨μ ν μ€ν νλ μμν¬λ μ¬λ°λ₯Έ μννΈμ¨μ΄ κ°λ°μ μ΄λλ νμνμ΄λ€.
μλ°μ€ν¬λ¦½νΈ μ ν리μΌμ΄μ μ΄ μ μ 볡μ‘ν΄μ§λ©΄μ μ»΄ν¬λνΈλ₯Ό κ°λ³μ μΌλ‘ μ μ λνκ³ λΆλ¦¬νλ μΌμ΄ λμ± μ€μν΄μ‘λ€. κ·Έλ° μ μμ μμ‘΄μ± μ£Όμ μ μ€μν ν ν¬λμ΄λ€.
TDD μ¬λ‘λ₯Ό λ€κΈ° μν΄ μ μ€ν©νΈ μ§ν₯ νλ‘κ·Έλλ° ν΄ν·μ κ°λ°νλ€. AOPλ₯Ό μ°λ©΄ μ 체 μ»΄ν¬λνΈλ₯Ό λ°κΎΈμ§ μκ³ λ μΊμ± κ°μ κ³΅ν΅ κΈ°λ₯μ μννΈμ¨μ΄ μ»΄ν¬λνΈμ λΌμ λ£μ μ μκ³ , μ½λλ₯Ό DRYνκ² μ μ§νλ©΄μλ λ¨μΌ μ± μ μμΉμ κ°κ³ κ°λ°©/νμ μμΉμ μΆ©μ€ν μ½λλ₯Ό λ§λ€ μ μλ€.
λ¦°ν°λ μ½λ κ²μ¬ λꡬλ‘, ꡬ문 μ€λ₯λ μ½λ© κ·μΉμ μ΄κΈ΄ μ½λλ₯Ό 미리 κ²½κ³ ν¨μΌλ‘μ¨ λ―Έμ μμ€μμ μ½λ λ―Ώμμ±μ λμΈλ€. μ격 λͺ―λ ꡬ문 μμ€μμ μ€μλ₯Ό μλ°©ν λ°©λ²μΌλ‘ κΆμ₯ν λ§νλ€.