<?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: ANUPAM SINGH</title>
    <description>The latest articles on DEV Community by ANUPAM SINGH (@anupam_singh_f8659ae497d7).</description>
    <link>https://dev.to/anupam_singh_f8659ae497d7</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%2F1934792%2Fa58feab8-9c45-4600-90f5-d9a7cfa03b0e.jpg</url>
      <title>DEV Community: ANUPAM SINGH</title>
      <link>https://dev.to/anupam_singh_f8659ae497d7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anupam_singh_f8659ae497d7"/>
    <language>en</language>
    <item>
      <title>Understanding Uncle Bob’s Component Principles</title>
      <dc:creator>ANUPAM SINGH</dc:creator>
      <pubDate>Mon, 15 Jun 2026 09:27:45 +0000</pubDate>
      <link>https://dev.to/anupam_singh_f8659ae497d7/understanding-uncle-bobs-component-principles-58f9</link>
      <guid>https://dev.to/anupam_singh_f8659ae497d7/understanding-uncle-bobs-component-principles-58f9</guid>
      <description>&lt;p&gt;Many developers learn Uncle Bob’s Component Principles from theory but struggle to understand where they apply in real projects.&lt;/p&gt;

&lt;p&gt;Let’s take a simple Android BLE Scanner application as an example.&lt;/p&gt;

&lt;p&gt;Imagine our project has two modules:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;core-ble-scanner&lt;br&gt;
feature-ble-scanner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;core-ble-scanner&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Contains:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BLE scanning logic&lt;br&gt;
Scan manager&lt;br&gt;
Bluetooth APIs&lt;br&gt;
Device discovery logic&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;feature-ble-scanner&lt;/strong&gt;&lt;br&gt;
Contains:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scan screen&lt;br&gt;
RecyclerView&lt;br&gt;
Compose UI&lt;br&gt;
Device list display&lt;br&gt;
User interactions&lt;/em&gt;&lt;br&gt;
Architecture:&lt;/p&gt;

&lt;p&gt;feature-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
core-ble-scanner&lt;/p&gt;

&lt;p&gt;The UI depends on the scanner logic.&lt;br&gt;
_&lt;br&gt;
&lt;strong&gt;1. Reuse/Release Equivalence Principle (REP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
If something can be reused, it should be packaged as a reusable component.&lt;/p&gt;

&lt;p&gt;Bad Example&lt;br&gt;
BLE scanning code is written directly inside the UI module.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feature-ble-scanner&lt;br&gt;
 ├── ScanScreen&lt;br&gt;
 ├── DeviceList&lt;br&gt;
 └── BluetoothScanner&lt;/em&gt;&lt;br&gt;
Now every feature that needs BLE scanning must copy the code.&lt;/p&gt;

&lt;p&gt;Better Example&lt;br&gt;
Move scanner logic to a separate component.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;core-ble-scanner&lt;br&gt;
 ├── BleScanner&lt;br&gt;
 ├── ScanManager&lt;br&gt;
 └── BluetoothRepository&lt;/em&gt;&lt;br&gt;
Now another feature can reuse it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feature-ble-scanner&lt;br&gt;
feature-device-pairing&lt;br&gt;
feature-device-diagnostics&lt;/em&gt;&lt;br&gt;
All use the same scanner component.&lt;/p&gt;

&lt;p&gt;Lesson&lt;br&gt;
Reusable code should live in its own reusable component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Common Closure Principle (CCP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
Things that change together should stay together.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
Suppose Android introduces a new BLE scanning API.&lt;/p&gt;

&lt;p&gt;What changes?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BleScanner&lt;br&gt;
ScanManager&lt;br&gt;
BluetoothRepository&lt;/em&gt;&lt;br&gt;
All these classes belong to scanning.&lt;/p&gt;

&lt;p&gt;They change for the same reason.&lt;/p&gt;

&lt;p&gt;Therefore they belong together.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;core-ble-scanner&lt;br&gt;
 ├── BleScanner&lt;br&gt;
 ├── ScanManager&lt;br&gt;
 └── BluetoothRepository&lt;/em&gt;&lt;br&gt;
The UI doesn’t change.&lt;/p&gt;

&lt;p&gt;So it should stay separate.&lt;/p&gt;

&lt;p&gt;Lesson&lt;br&gt;
Keep BLE logic together because it changes together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Common Reuse Principle (CRP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
Don’t force modules to depend on things they don’t need.&lt;/p&gt;

&lt;p&gt;Bad Example&lt;br&gt;
&lt;em&gt;core-ble-scanner&lt;br&gt;
 ├── BleScanner&lt;br&gt;
 ├── ScanManager&lt;br&gt;
 ├── ScanScreen&lt;br&gt;
 ├── DeviceAdapter&lt;br&gt;
 └── DeviceCard&lt;/em&gt;&lt;br&gt;
Now another feature only needs scanning.&lt;/p&gt;

&lt;p&gt;But it must also depend on:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Compose UI&lt;br&gt;
RecyclerView&lt;br&gt;
UI resources&lt;/em&gt;&lt;br&gt;
which it doesn’t need.&lt;/p&gt;

&lt;p&gt;Better Example&lt;br&gt;
&lt;em&gt;core-ble-scanner&lt;br&gt;
 ├── BleScanner&lt;br&gt;
 └── ScanManager&lt;br&gt;
feature-ble-scanner&lt;br&gt;
 ├── ScanScreen&lt;br&gt;
 ├── DeviceCard&lt;br&gt;
 └── DeviceList&lt;/em&gt;&lt;br&gt;
Each module depends only on what it needs.&lt;/p&gt;

&lt;p&gt;Lesson&lt;br&gt;
Separate reusable logic from UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Acyclic Dependencies Principle (ADP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
Dependencies should not form circles.&lt;/p&gt;

&lt;p&gt;Bad Example&lt;br&gt;
&lt;em&gt;feature-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
core-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
feature-ble-scanner&lt;/em&gt;&lt;br&gt;
How can this happen?&lt;/p&gt;

&lt;p&gt;Become a Medium member&lt;br&gt;
Suppose:&lt;/p&gt;

&lt;p&gt;_core-ble-scanner&lt;br&gt;
_calls&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ScanScreen.showError()&lt;/em&gt;&lt;br&gt;
Now the core module depends on the feature module.&lt;/p&gt;

&lt;p&gt;And the feature module already depends on core.&lt;/p&gt;

&lt;p&gt;We created a cycle.&lt;/p&gt;

&lt;p&gt;Better Example&lt;br&gt;
&lt;em&gt;feature-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
core-ble-scanner&lt;/em&gt;&lt;br&gt;
Only one direction.&lt;/p&gt;

&lt;p&gt;Core never knows about UI.&lt;/p&gt;

&lt;p&gt;Lesson&lt;br&gt;
Core modules should not depend on feature modules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Stable Dependencies Principle (SDP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
Depend on stable things.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
UI changes frequently.&lt;/p&gt;

&lt;p&gt;Maybe today:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;RecyclerView&lt;/em&gt;&lt;br&gt;
Tomorrow:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jetpack Compose&lt;/em&gt;&lt;br&gt;
Next month:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Different design&lt;/em&gt;&lt;br&gt;
UI is unstable.&lt;/p&gt;

&lt;p&gt;BLE scanning logic changes less often.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BleScanner&lt;br&gt;
ScanManager&lt;br&gt;
BluetoothRepository&lt;/em&gt;&lt;br&gt;
are relatively stable.&lt;/p&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feature-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
core-ble-scanner&lt;/em&gt;&lt;br&gt;
is correct.&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;core-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
feature-ble-scanner&lt;/em&gt;&lt;br&gt;
Lesson&lt;br&gt;
Unstable UI should depend on stable business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Stable Abstractions Principle (SAP)&lt;/strong&gt;&lt;br&gt;
Idea&lt;br&gt;
Stable modules should expose abstractions.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
Instead of exposing implementation:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;class AndroidBleScanner&lt;/em&gt;&lt;br&gt;
Expose an interface.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;interface BleScanner {&lt;br&gt;
    fun startScan()&lt;br&gt;
    fun stopScan()&lt;br&gt;
}&lt;/em&gt;&lt;br&gt;
Implementation:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;class AndroidBleScanner : BleScanner&lt;/em&gt;&lt;br&gt;
Now future implementations can be added.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;FakeBleScanner&lt;br&gt;
MockBleScanner&lt;br&gt;
AndroidBleScanner&lt;/em&gt;&lt;br&gt;
without changing consumers.&lt;/p&gt;

&lt;p&gt;Lesson&lt;br&gt;
&lt;strong&gt;Stable components should expose interfaces, not concrete implementations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Architecture&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;core-ble-scanner&lt;br&gt;
│&lt;br&gt;
├── BleScanner&lt;br&gt;
├── AndroidBleScanner&lt;br&gt;
├── ScanManager&lt;br&gt;
├── BluetoothRepository&lt;br&gt;
└── Models&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feature-ble-scanner&lt;br&gt;
│&lt;br&gt;
├── ScanScreen&lt;br&gt;
├── DeviceList&lt;br&gt;
├── DeviceCard&lt;br&gt;
└── ViewModel&lt;/em&gt;&lt;br&gt;
Dependency direction:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feature-ble-scanner&lt;br&gt;
        ↓&lt;br&gt;
core-ble-scanner&lt;/em&gt;&lt;br&gt;
This architecture follows all six of Uncle Bob’s Component Principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reusable scanner logic is isolated&lt;/li&gt;
&lt;li&gt;BLE-related changes stay together&lt;/li&gt;
&lt;li&gt;UI is not forced on other features&lt;/li&gt;
&lt;li&gt;No circular dependencies&lt;/li&gt;
&lt;li&gt;UI depends on stable logic&lt;/li&gt;
&lt;li&gt;Stable logic exposes abstractions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s exactly why many modern Android projects separate core modules from feature modules. This isn’t just about keeping code organized — it makes the application easier to maintain, test, and extend as new BLE features are added.&lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>componentsprinciple</category>
      <category>cleanarchiecture</category>
      <category>unclebob</category>
    </item>
  </channel>
</rss>
