주말 아침 - 주간 닷넷 #25

한 주 동안 .NET 생태계에서 있었던 주요 이슈와 아티클, 기술 트렌드를 정리해 소개합니다.


:pushpin: EF Core의 스마트 쿼리 분할: SmartSplitQueryInterceptor

https://blog.peakcyber.com/smart-query-splitting-in-entity-framework-core-smartsplitqueryinterceptor-1373e6■■82fc

  • 저자: Semih Kalınlı
  • 태그: #efcore #performance #interceptor

주요 내용

  • Single Query의 Cartesian Explosion과 Split Query의 라운드트립 사이 트레이드오프 분석
  • IQueryExpressionInterceptor로 LINQ Expression Tree를 분석해 분할 전략을 동적으로 결정
  • 초기 Include 카운트 휴리스틱이 .Take(10) 케이스에서 실패한 사례
  • Gridify가 .Take(limit)을 closure 기반 ParameterExpression으로 감싸 평가가 어려운 문제와 우회
  • HasTake 감지 + Include 임계값(8, 20) 조합으로 페이지네이션 응답 ~70% 개선

:pushpin: 1~N-1 범위 N개 정수 배열에서 중복 찾기

  • 저자: Raymond Chen
  • 태그: #algorithm #puzzle windows

주요 내용

  • N개 정수가 1~N-1 범위에 있을 때 O(N) 시간 + 상수 공간으로 중복 찾는 인터뷰 문제
  • 배열을 1-기반 인덱스 링크드 리스트로 보고 부호 비트를 방문 플래그로 활용하는 풀이
  • 부호 비트 트릭이 사실상 O(N) 보조 비트라는 솔직한 각주
  • 함수 그래프 위에서 Floyd 토끼와 거북이(cycle detection)를 적용한 더 우아한 해법
  • "두 노드가 같은 목적지를 가리키는 지점"으로 사이클 시작점을 찾는 관점

:pushpin: .NET의 아키텍처 테스트

https://mareks-082.medium.com/architectural-tests-in-net-1bd5d19b0ba8

  • 저자: Marek Sirkovský
  • 태그: #architecture #testing #roslyn

주요 내용

  • 위키의 아키텍처 다이어그램은 강제력이 없으므로 실행 가능한 테스트가 필요
  • ArchUnitNET, NetArchTest, NetArchTest.eNhancedEdition의 fluent API 비교 (Service→Controller 의존 금지 등)
  • dbContext.Model.GetEntityTypes() 리플렉션으로 EF Core 엔티티 명명 규칙 같은 커스텀 컨벤션 검사
  • Roslyn 분석기로 DateTime.Now 금지 + Microsoft.CodeAnalysis.BannedApiAnalyzers + BannedSymbols.txt
  • NDepend CQLinq, Metalama NamespaceFabric.CanOnlyBeUsedFrom, SonarQube/Roslynator/Meziantou.Analyzer 트레이드오프

:pushpin: 도움이 되는 추상화, 해가 되는 추상화

  • 저자: Bipin Joshi
  • 태그: #abstraction #design #architecture

주요 내용

  • IOrderService 같은 경계 인터페이스(좋음) vs 단일 구현뿐인 제네릭 IRepository<T>(나쁨) 대조
  • Controller→Service→Manager→Repository→DataProvider로 이어지는 단일 구현 인터페이스 미궁
  • context.Orders.ToList()이 10건일지 1만 건일지 알 수 없는 EF의 누수 추상화
  • IServiceManager 같은 막연한 명명과 얕은 도메인 이해의 연결 고리
  • 휴리스틱: 일반화할 구체 타입이 둘 이상 생기기 전에는 추상화를 도입하지 말 것

:pushpin: EF Core 쿼리 변환: 왜 일부 LINQ는 SQL이 되지 않는가

  • 저자: Ali Hamza Ansari
  • 태그: #efcore linq #translation

주요 내용

  • PostgreSQL 향수 인벤토리 예제로 변환 가능/불가 케이스 12가지를 코드와 SQL로 비교
  • 변환 가능: 가격 비교, 문자열 연산, DateTime 속성, 외부 리스트 Contains
  • 변환 불가: 사용자 정의 메서드, Regex, Reflection, 파일 시스템 접근, Random
  • SQL이 .NET 런타임 의미론을 표현하지 못하는 근본 미스매치
  • 변환 실패 시 클라이언트 평가로 빠지지 않게 명시적으로 처리하는 방법

:pushpin: .NET 구성을 시작 시점에 검증하기

주요 내용

  • 잘못된 구성이 엔드포인트 호출 시점에야 NullReferenceException으로 드러나는 문제
  • EmailOptions[Required] 어노테이션 + AddOptionsWithValidateOnStart() + ValidateDataAnnotations()
  • AbstractValidator<T>IValidateOptions<T>를 잇는 AbstractOptionsValidator<T> 베이스로 FluentValidation 통합
  • 검증 실패 시 호스트 시작 단계에서 Microsoft.Extensions.Hosting.Internal.Host[11] 예외로 즉시 실패
  • 데이터 어노테이션 vs FluentValidation 두 접근의 코드 구성과 등록 흐름

:pushpin: EF Core: Lazy Loading, Eager Loading, Explicit Loading

https://medium.com/@remigiuszzalewski/ef-core-lazy-loading-eager-loading-and-explicit-loading-7594c6aae4fa

  • 저자: Remigiusz Zalewski
  • 태그: #efcore #loading #performance

주요 내용

  • e-commerce API(Customer/Order/OrderItem/Product/Category)로 세 가지 로딩 전략을 비교
  • Lazy Loading 사용 시 311개 쿼리가 발행되는 N+1 발생
  • Include()/ThenInclude() 조합 + AsSplitQuery()로 Cartesian Explosion 회피, ~5개 쿼리로 축소
  • Entry().Collection().LoadAsync() / Entry().Reference().LoadAsync()로 조건부 명시적 로딩
  • 프로덕션 API 권장: Eager + Split Query

:pushpin: 빌드 타임 반란: .NET 메인테이너의 반격

https://tonyqus.medium.com/the-build-time-rebellion-when-net-maintainers-fought-back-64dcd2c02dd3

  • 저자: Tony Qu
  • 태그: #opensource community #sustainability

주요 내용

  • 2018 년 Fody의 Simon Cropp가 빌드 인터럽션으로 스폰서십을 유도한 “honesty system” 사례
  • 2023년 Moq에서 Daniel Cazzulino가 Git 사용자 이메일을 해시 수집한 SponsorLink 사건
  • Moq 사건 발생 48시간 내에 진행된 기업 단위 블랙리스팅의 전개
  • 메인테이너 번아웃과 허용 라이선스 하 기업의 무임승차라는 근본 원인
  • 빌드 깨기·텔레메트리 같은 기술적 강제는 OSS 지속가능성을 해결하지 못하고 신뢰만 훼손한다는 결론

:bookmark_tabs: 가벼운 읽을거리

후보 항목 중 이슈로 선정되지 않은 가벼운 읽을거리들


.NET 10에서 .sln에서 .slnx로 마이그레이션

  • .NET 10에서 dotnet new sln이 XML 기반 .slnx를 기본으로 채택, 35줄 → 7줄로 축소
  • dotnet sln migrate CLI, VS 2022 17.13+, Rider 2024.3+ 마이그레이션 경로

.ToList() 호출을 멈춰라

  • 리포지토리에서 IEnumerable<T> 반환이 조기 머터리얼라이즈를 유발하는 안티패턴
  • IQueryable<T>를 유지해 WHERE/ORDER BY/LIMIT가 SQL로 합성되도록 비교

Entity Framework Extensions로 EF Core 성능 끌어올리기

  • ZZZ Projects의 Z.EntityFramework.Extensions.EFCore의 BulkInsert/Update/Merge/Synchronize API 소개
  • PostgreSQL 10,000건 기준 16~39배 성능 향상 수치 (상용 라이선스)

현대 .NET에서 Repository 패턴이 여전히 필요한가

  • DbContext가 이미 Unit-of-Work + Repository를 구현한다는 Microsoft 문서 관점
  • DbContext 직접 사용 vs Repository 추상화의 단일 앱/공유 라이브러리별 트레이드오프

소스 제너레이터 기반 CQRS 라이브러리 Mevora 리뷰

  • 누락된 핸들러를 빌드 시점에 감지하는 소스 제너레이터 기반 CQRS 라이브러리
  • Request/Processor 아키텍처, fluent validation, Pub/Sub 메시징, DI 통합 예제

Kiro Spec-First로 Mediator 파이프라인 프로젝트 업그레이드

  • 1년 묵은 MediatR 프로젝트를 .NET 9 → 10으로 옮기며 Kiro IDE의 Spec-First 워크플로 3라운드 반복
  • MediatR 13.0+ 라이선스 변경(RPL-1.5)으로 12.5.0 유지 결정과 첫 반복 한계의 솔직한 평가

EF Core 쿼리 성능: 빠른 쿼리 작성법

  • .Include() 남용, 전체 엔티티 페치, ToList() 선행 호출, 지연 실행 무시 같은 안티패턴 정리
  • 프로젝션, AsNoTracking(), AsSplitQuery(), 페이지네이션, 인덱스, 조기 필터링 권장

지갑 전부 넘기지 말 것: .NET DTO 설명

  • User 엔티티의 PasswordHash 노출 같은 보안/성능/결합도 리스크와 DTO 도입 근거
  • record 기반 응답 DTO + Data Annotations 요청 DTO + Select 프로젝션 vs AutoMapper/Mapster 비교

C#의 Span과 Memory 차이

  • Span<T> 스택 ref struct vs Memory<T> 힙 struct, 비동기 호환성 비교
  • Substring 할당과 text.AsSpan(0, 5) 제로 할당 뷰의 차이
2개의 좋아요