По поводу отделения GenServer-а от структуры данных - я думаю так, если структура данных и вычисления представляют какой-то интерес вне GenServer-а, т.е. другой человек может получить от этого профит - имеет смысл разделять, если не представляет интереса, то разделять не стоит, а тестировать можно и через вызовы handle_call напрямую.
Кроме того, state в одном месте а logic в другой никак не может соотнестись с solid, потому что с точки зрения архитектуры данные без операций над ними не имеют смысла
Кроме того, у генсервера есть стандартный функционал разделения, для этого одним из параметров GenServer.start_link указывается модуль с коллбэками
Что-то я не понял, ты про первый агрумент?
Если я в модуле (Stack), где описываю генсервер, вместо GenServer.start_link(__MODULE__, …) напишу GenServer.start_link(StackModuleCallbacks, …) это будет вызывать куда больше вопросов и путаницы
с apply хотя бы видно, что у генсервера есть коллбэк, и какой модуль он вызывает.
Если колбэки передать в start_link, в которые почти никто никогда не смотрит - то это вызовет путанницу, т.к. зачем вообще описывать коллбэки, если они в другом модуле?