# Devlog: Author Resolution at the CLI Layer During Book Import (PR #116)

### Devlog: Author Resolution at the CLI Layer During Book Import (PR #116)

On **December 15, 2025**, I hit a classic “architecture smells like smoke” moment while importing books via ISBN scan: **author names arrive as strings**, but authors in my system are **entities with IDs**. That sounds simple until you remember the universe’s favorite prank: **multiple humans can share the same name**.

So I refactored the flow so the **CLI handles author resolution interactively** (where user interaction belongs), and the **mapper goes back to being a boring, pure transformer** (where side effects don’t belong).

---

## The friction: “Sam Newman” is not a unique identifier

When you scan an ISBN, Google Books might return authors like:

* `"Sam Newman"`
    

The system needs to decide:

* Does this author already exist?
    
* If yes… **which one** if there are duplicates?
    
* If no… create a new author
    

Originally, I had author creation buried inside the infrastructure mapper:

```java
authorFacade.createAuthorsIfNotExist(response.authors());  // no user interaction possible
```

That created two problems:

1. **Mappers shouldn’t have side effects** (they should map data, not mutate the world).
    
2. **The CLI can’t prompt the user** if the decision is happening deep inside mapping code.
    

Result: authors could be silently duplicated during imports.

---

## The behavior change: prompts where prompts belong

### Before

Scan ISBN → metadata → mapper creates authors automatically → book saved (duplicates possible)

### After

Scan ISBN → metadata → **CLI resolves authors**:

* If multiple matches exist:
    
    * user selects existing author, or chooses to create a new one
        
* author IDs are collected
    
* book creation proceeds with resolved IDs
    

Now the import looks like:

```plaintext
Multiple authors found. Select one or create new:
[1] Sam Newman (ID: 42) - [Building Microservices: Designing Fine-Grained Systems,Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith]
[2] Sam Newman (ID: 87) - [The Tree that Would]
[0] Create new author
```

---

## The key API shift: make dependencies explicit

This was the big contract change:

```java
// Before
void createBookFromMetaData(BookMetaDataResponse response, String isbn, Long shelfId);

// After
void createBookFromMetaData(BookMetaDataResponse response, List<Long> authorIds, String isbn, Long shelfId);
```

Translation: **Book creation no longer secretly resolves authors**.  
The caller (CLI, or later a web API) must provide the chosen author IDs.

That’s a feature, not a chore.

---

## Architectural meaning: Hexagonal sanity restored

This refactor nudges the system back toward good boundaries:

* **CLI (BookCommands):** user interaction + resolution logic
    
* **Facade / domain use cases:** orchestrate book creation with provided IDs
    
* **Mapper:** pure transformation again
    
* **Repository:** persist what it’s given
    

Bonus: the book creation path is now reusable for other UIs (like a web API) without dragging prompts along for the ride.

---

## The new flow (cleaner, testable, explicit)

1. Scan ISBN
    
2. Fetch metadata
    
3. `createAuthorsFromMetaData()` in CLI:
    
    * parse names
        
    * find duplicates
        
    * prompt user if needed
        
    * return `List<Long> authorIds`
        
4. Confirm book
    
5. Create book with resolved author IDs
    

---

## The “still needs cleanup” pile (aka: the tax)

This PR is **in progress**, and it surfaced some cleanup items before merge:

* Remove commented-out multi-scan code (replace with a real exception if disabled)
    
* Replace the “0 means create new” **magic number** with `Optional<Long>` or a constant
    
* Stop using unsafe `Optional.get()` in `getAuthorById`
    
* Remove/implement an empty stub method returning `Optional.empty()`
    
* Move `System.out.println` out of repositories and back into CLI
    

These are all small, but worth fixing before PR #116 lands.

---

## Portfolio / interview punchline

This refactor is really about one idea:

**Put decisions where the information and responsibility live.**

If the user needs to choose between duplicate authors, that’s a **presentation-layer concern**. If a mapper is creating records, that’s a **leaky abstraction with hidden side effects**. Passing `authorIds` makes the dependency explicit, the system more testable, and the architecture more adaptable to future UIs.

The universe will still contain multiple “Sam Newman”s, but now my CLI won’t pretend it’s never heard of ambiguity.
