V2 → V3 마이그레이션 가이드
Caffeine V3는 AAS-First 아키텍처로 전환하면서 여러 Breaking Change가 발생했습니다. 이 가이드는 V2 코드를 V3으로 마이그레이션하는 단계별 절차를 안내합니다.
주요 변경 사항 요약
| 항목 | V2 | V3 |
|---|---|---|
| 이벤트 | MediatR + IRxEventBus + SignalR | ICaffeineEventBus (단일) |
| 클라이언트 | ICaffeineClient (비대) | ICaffeineClient + 6개 Operations |
| 드라이버 | IDriverModule + IDriverCapabilities + IUpdateableDriver | IDriverModule (통합) + DriverBase |
| DI 등록 | AddCaffeineInfrastructure() | Feature Module Opt-in 체이닝 |
| SemanticId | AasConstants.SemanticIds | IdtaSemanticIds (IDTA 공식) |
| 테스트 | Moq | NSubstitute |
| 빌더 | CaffeineBuilder (구체) | ICaffeineBuilder (인터페이스) |
1. ICaffeineClient ISP 분리
// V2
var tag = await client.ReadTagAsync("Temperature");
var alarms = await client.GetAlarmsAsync();
// V3
var tag = await client.Tags.ReadAsync("Temperature");
var alarms = await client.Alarms.GetActiveAsync();
V3 Operations 인터페이스
| V3 인터페이스 | 용도 |
|---|---|
client.Aas | AAS Shell/Submodel 조회 |
client.Tags | 태그 읽기/쓰기/구독 |
client.Alarms | 알람 관리 |
client.Drivers | 드라이버 상태 |
client.History | 이력 조회 |
client.Predictive | 예지보전 |
2. MediatR → ICaffeineEventBus
// V2 (MediatR)
await mediator.Send(new CreateDeviceCommand { ... });
await mediator.Publish(new DeviceCreatedEvent { ... });
// V3 (ICaffeineEventBus)
await eventBus.SendAsync(new CreateDeviceCommand { ... });
eventBus.Publish(new DeviceCreatedEvent { ... });
3. IDriverModule 통합
// V2 — 3개 인터페이스
public class MyDriver : IDriverModule, IDriverCapabilities, IUpdateableDriver
// V3 — DriverBase 상속
public class MyDriver : DriverBase
{
// ReadBytesAsync, WriteBytesAsync만 구현
// HealthStream, State 관리는 DriverBase가 제공
}
메서드 시그니처 변경
// V2
Task<int> ReadBytesAsync(string address, byte[] buffer);
Task WriteBytesAsync(string address, byte[] data);
// V3 (Zero-Allocation)
Task<int> ReadBytesAsync(string address, Memory<byte> buffer);
Task WriteBytesAsync(string address, ReadOnlyMemory<byte> data);
4. DI 등록
// V2
services.AddCaffeineInfrastructure(config); // God Method
// V3 (Feature Module Opt-in)
services
.AddCaffeineCore(config)
.AddCaffeineAas()
.AddCaffeineAasMapping(m => m.UseEclassDefaults())
.AddCaffeineAasProtocol(p => p.ExposeViaRest("/api/v3/aas"))
.AddCaffeineTypeDb()
.AddCaffeinePredictive()
.AddCaffeineMLPipeline()
.AddCaffeineObservability("caffeine-v3");
5. SemanticId 변경
// V2 — AasConstants.SemanticIds는 V3에서 제거됨
var id = AasConstants.SemanticIds.Temperature; // 컴파일 오류
// V3
var id = IdtaSemanticIds.Temperature; // IDTA 공식
6. 테스트 마이그레이션
// V2 (Moq)
var mock = new Mock<IDriverModule>();
mock.Setup(m => m.DriverId).Returns("test");
// V3 (NSubstitute)
var mock = Substitute.For<IDriverModule>();
mock.DriverId.Returns("test");
7. SignalR → gRPC Streaming
V3에서 SignalR Hub는 제거되었습니다. gRPC Streaming으로 대체합니다.
// V2 (SignalR)
await hubConnection.InvokeAsync("SubscribeTag", "Temperature");
// V3 (gRPC Streaming)
await foreach (var tag in client.Tags.SubscribeAsync("Temperature"))
{
// 태그 변경 처리
}
전체 변환 규칙 표
| V2 코드 | V3 코드 |
|---|---|
client.ReadTagAsync() | client.Tags.ReadAsync() |
client.ReadTagGrpcAsync() | client.Tags.ReadAsync() |
client.SubscribeTagAsync() | 제거 (gRPC Streaming) |
client.GetAlarmsAsync() | client.Alarms.GetActiveAsync() |
client.GetDriversAsync() | client.Drivers.ListAsync() |
MediatR ICommand<T> | eventBus.SendAsync<T>() |
MediatR IQuery<T> | 직접 서비스 호출 |
IRxEventBus | ICaffeineEventBus |
Channel<T> 워커 | EventBus + BackgroundService |
byte[] | Memory<byte> / ReadOnlyMemory<byte> |
Mock<T> | Substitute.For<T>() |
AddCaffeineInfrastructure() | Feature Module 개별 호출 |
TypeDbPredictiveAlert | PredictiveMaintenanceAlert (IDTA 02048) |