본문으로 건너뛰기

V2 → V3 마이그레이션 가이드

Caffeine V3는 AAS-First 아키텍처로 전환하면서 여러 Breaking Change가 발생했습니다. 이 가이드는 V2 코드를 V3으로 마이그레이션하는 단계별 절차를 안내합니다.

주요 변경 사항 요약​

항목V2V3
이벤트MediatR + IRxEventBus + SignalRICaffeineEventBus (단일)
클라이언트ICaffeineClient (비대)ICaffeineClient + 6개 Operations
드라이버IDriverModule + IDriverCapabilities + IUpdateableDriverIDriverModule (통합) + DriverBase
DI 등록AddCaffeineInfrastructure()Feature Module Opt-in 체이닝
SemanticIdAasConstants.SemanticIdsIdtaSemanticIds (IDTA 공식)
테스트MoqNSubstitute
빌더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.AasAAS 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>직접 서비스 호출
IRxEventBusICaffeineEventBus
Channel<T> 워커EventBus + BackgroundService
byte[]Memory<byte> / ReadOnlyMemory<byte>
Mock<T>Substitute.For<T>()
AddCaffeineInfrastructure()Feature Module 개별 호출
TypeDbPredictiveAlertPredictiveMaintenanceAlert (IDTA 02048)