Очевидный ответ на этот вопрос - знать, как конструировать распределённые приложения, конечно же. Это отдельный целый раздел знаний, там много своих особенностей, не скажешь просто так.
На мой взгляд, самое полезное, что нужно осознавать при переходе с монолита на распределённое приложение - это что поток данных между отдельными частями распределённого приложения прерывается и меняет вид транспорта.
Если в монолите вы могли просто вызвать метод компонента из соседнего модуля, то теперь вам придётся уметь делать RPC или вообще работать с удалённым компонентом как со сторонним сервисом, через API.
Если в монолите вы могли просто передать структуру данных в качестве аргумента вызова функции, а потом получить её обратно в качестве возвращаемого значения, теперь надо эту структуру данных сериализовать для передачи по сети, а результат потом десериализовать обратно. А так как для маршаллинга пригодны, грубо говоря, только структуры данных, а не объекты с поведением, у нас вынужденно растёт количество сущностей на границах модулей, и появляются новые слои абстракции.
Более того, так как общение между частями распределённого приложения производится по сети, возрастают требования к fault tolerance. Вообще больше нельзя ожидать, что вызов соседнего компонента завершится успешно. Везде нужно добавлять обработку ожидаемых ошибок и как-то подстраивать поведение собственного компонента под возможный сбой соседнего. Про fault tolerance в веб-приложениях (которые можно считать своего рода разновидностью распределённых) мне очень понравилось, как написано в Release It! Майкла Нейгарда.
Ну и, конечно же, если ваше приложение выполняет какие-то сложные алгоритмы, и алгоритм задействует сразу несколько компонентов вашей распределённой системы, то мы попадаем в увлекательную сферу распределённых алгоритмов, про которую, например, Нэнси Линч в 1997 году написала свою Distributed Algorithms, маленькую такую книжку в 900 страниц толщиной.