<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Van Hung Nguyen</title>
    <description>The latest articles on DEV Community by Van Hung Nguyen (@nguyenvhung9420).</description>
    <link>https://dev.to/nguyenvhung9420</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F247045%2F059a12d9-95c8-40c4-822c-20c7a52cd2ff.jpeg</url>
      <title>DEV Community: Van Hung Nguyen</title>
      <link>https://dev.to/nguyenvhung9420</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nguyenvhung9420"/>
    <language>en</language>
    <item>
      <title>Clean Architecture: iOS Projektstruktur und Ebenen</title>
      <dc:creator>Van Hung Nguyen</dc:creator>
      <pubDate>Fri, 20 Mar 2026 08:06:47 +0000</pubDate>
      <link>https://dev.to/nguyenvhung9420/clean-architecture-ios-projektstruktur-und-ebenen-25io</link>
      <guid>https://dev.to/nguyenvhung9420/clean-architecture-ios-projektstruktur-und-ebenen-25io</guid>
      <description>&lt;h2&gt;
  
  
  Clean Architecture: Projektstruktur und Ebenen
&lt;/h2&gt;

&lt;p&gt;In einem professionellen iOS-Projekt ist die Ordnerstruktur deine &lt;strong&gt;erste Verteidigungslinie&lt;/strong&gt; gegen „Spaghetti-Code“. Während die Kreise der Clean Architecture konzeptionell sind, muss deine Struktur im Xcode-Projekt oder im Swift Package (SPM) physisch vorhanden sein und strikt durchgesetzt werden.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Das Mapping: Theorie vs. Ordner
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Clean-Ebene&lt;/th&gt;
&lt;th&gt;Ordnername&lt;/th&gt;
&lt;th&gt;Inhalt&lt;/th&gt;
&lt;th&gt;Abhängigkeitsregel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Entities&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Domain/Entities&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reine Swift-Structs (z. B. &lt;code&gt;Translation&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Keine.&lt;/strong&gt; Pures Swift.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Domain/UseCases&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Logik-Protokolle und Interaktoren.&lt;/td&gt;
&lt;td&gt;Nur &lt;strong&gt;Entities&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gateways&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Domain/Interfaces&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Repository-Protokolle&lt;/strong&gt; (z. B. &lt;code&gt;TranslationRepository&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;Nur &lt;strong&gt;Entities&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Data/Repositories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Konkrete Repository-Implementierungen.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Domain-Ebene.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Data/DataSources&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;API-Clients, Core Data Manager, DTOs.&lt;/td&gt;
&lt;td&gt;Externe Frameworks (Alamofire, CoreData).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Presentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Presentation/UI&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SwiftUI Views, ViewModels, Coordinators.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Domain-Ebene.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  2. Die empfohlene Projektstruktur
&lt;/h3&gt;

&lt;p&gt;Für ein Projekt mit deiner Komplexität (Bibel-App, Core Data, mehrere Sprachen) ist ein &lt;strong&gt;modularisierter SPM-Ansatz&lt;/strong&gt; ideal. Wenn du ein einzelnes Target nutzt, verwende diese Hierarchie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/App (Der Composition Root)
├── DependencyInjection/ (Swinject oder custom Container)
└── AppLauncher.swift (App-Struktur)

/Domain (Das "Gehirn")
├── Entities/ (Translation.swift, Verse.swift)
├── UseCases/ (FetchVersesUseCase.swift, BookmarkVerseUseCase.swift)
└── Interfaces/ (TranslationRepositoryProtocol.swift)

/Data (The "Arbeiter")
├── Repositories/ (TranslationRepository.swift)
├── DataSources/
│   ├── Remote/ (APIClient.swift, TranslationDTO.swift)
│   └── Local/ (CoreDataStack.swift, CDTranslation+Mapping.swift)
└── Mappers/ (DTOToEntityMapper.swift)

/Presentation (Das "Gesicht")
├── Scenes/ (Die UI-Screens)
│   ├── TranslationList/
│   │   ├── TranslationListView.swift
│   │   └── TranslationListViewModel.swift
│   └── TranslationDetail/ ...
├── Components/ (Wiederverwendbare SwiftUI Views)
└── Coordinator/ (Navigationslogik)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Der Abhängigkeitsfluss (Die "Rule of Inward")
&lt;/h3&gt;

&lt;p&gt;Die wichtigste Erkenntnis für einen Senior-Entwickler ist, dass Abhängigkeiten &lt;strong&gt;nur nach innen&lt;/strong&gt; zeigen dürfen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain ist König:&lt;/strong&gt; Sie weiß nichts über SwiftUI, Core Data oder Firebase. Wenn du deine Domain-Unit-Tests nicht ohne &lt;code&gt;UIKit&lt;/code&gt; ausführen kannst, ist deine Architektur „undicht“ (Leaky Architecture).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Die Repository-Brücke:&lt;/strong&gt; Die Data-Ebene implementiert die in der Domain definierten Protokolle.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Domain:&lt;/em&gt; „Ich brauche einen Weg, um Übersetzungen zu erhalten.“ (&lt;strong&gt;Protokoll&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Data:&lt;/em&gt; „Ich hole sie aus Core Data.“ (&lt;strong&gt;Implementierung&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Die ViewModel-Brücke:&lt;/strong&gt; Das ViewModel ruft den UseCase auf, der eine Entity zurückgibt. Das ViewModel konvertiert diese Entity dann in ein &lt;strong&gt;ViewItem&lt;/strong&gt; (ein für die UI optimiertes Struct).&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Warum Mappers nutzen? (Data vs. Domain)
&lt;/h3&gt;

&lt;p&gt;In deiner App hat ein Core Data-Objekt oft Altlasten (Optionals, &lt;code&gt;NSManagedObject&lt;/code&gt;-Logik). Mappers halten die Domain sauber.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CoreDataTranslation&lt;/code&gt; (Data Layer):&lt;/strong&gt; An Core Data gebunden, optionale Strings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Translation&lt;/code&gt; (Domain Layer):&lt;/strong&gt; Sauber, nicht-optional, ein immutables Struct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Die Lösung:&lt;/strong&gt; Erstelle in &lt;code&gt;Data/Mappers&lt;/code&gt; eine einfache Extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;CoreDataTranslation&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Translation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Mapping von DB-Modell zu sauberem Domain-Modell&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Translation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuidString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Unbekannt"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Senior-Strategie: Modularisierung (SPM)
&lt;/h3&gt;

&lt;p&gt;Bei über 5 Jahren Erfahrung ist es ratsam, diese Ebenen in &lt;strong&gt;separate Swift Packages&lt;/strong&gt; auszulagern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Domain&lt;/code&gt; Package:&lt;/strong&gt; Null Abhängigkeiten. Extrem schnell zu testen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Data&lt;/code&gt; Package:&lt;/strong&gt; Hängt nur von der Domain ab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UI&lt;/code&gt; Package:&lt;/strong&gt; Hängt nur von der Domain ab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Der Vorteil:&lt;/strong&gt; Es verhindert physisch, dass jemand versehentlich ein Datenbank-Modell in eine View importiert. Der Compiler würde den Dienst verweigern.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>codequality</category>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>Recommended iOS Project Structure by Clean Architecture</title>
      <dc:creator>Van Hung Nguyen</dc:creator>
      <pubDate>Fri, 20 Mar 2026 07:54:05 +0000</pubDate>
      <link>https://dev.to/nguyenvhung9420/recommended-ios-project-structure-by-clean-architecture-2i81</link>
      <guid>https://dev.to/nguyenvhung9420/recommended-ios-project-structure-by-clean-architecture-2i81</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Recommended Project Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a project with your level of complexity (Bible app, multiple translations, Core Data), a Modularized SPM approach is best. If you prefer a single target, use this folder hierarchy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/App (The Composition Root)
├── DependencyInjection/ (Swinject or custom Container)
└── AppLauncher.swift (App Struct)

/Domain (The "Brain")
├── Entities/ (Translation.swift, Verse.swift)
├── UseCases/ (FetchVersesUseCase.swift, BookmarkVerseUseCase.swift)
└── Interfaces/ (TranslationRepositoryProtocol.swift)

/Data (The "Worker")
├── Repositories/ (TranslationRepository.swift)
├── DataSources/
│   ├── Remote/ (APIClient.swift, TranslationDTO.swift)
│   └── Local/ (CoreDataStack.swift, CDTranslation+Mapping.swift)
└── Mappers/ (DTOToEntityMapper.swift)

/Presentation (The "Face")
├── Scenes/ (The UI screens)
│   ├── TranslationList/
│   │   ├── TranslationListView.swift
│   │   └── TranslationListViewModel.swift
│   └── TranslationDetail/ ...
├── Components/ (Reusable SwiftUI Views)
└── Coordinator/ (Navigation logic)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
