¿Los bloques de finalización nesteds son un signo de mal layout?

Tengo un método que llama a tres funciones que cada una hace una request a Firebase y devuelve datos en un controller de finalización. Una vez que se devuelven los datos de 2 de los controlleres de finalización, invoco otro método para pasar los datos y enviar un resultado válido. ¿Los bloques de anidamiento como este son un signo de layout deficiente?

func fetchNearbyUsers(for user: User, completionHandler: usersCompletionHandler?) { self.fetchAllUsers(completionHandler: { (users: [User]) in ChatProvider.shanetworkingInstance.fetchAllChatrooms(completionHandler: { (chatrooms: [Chatroom]) in self.validateNewUsers(currentUser: user, users: users, chatrooms: chatrooms, completionHandler: { (validUsers: [User]) in guard validUsers.isEmpty == false else { completionHandler?([]) return } completionHandler?(validUsers) }) }) }) } 

// Otros metodos

  func fetchAllUsers(completionHandler: usersCompletionHandler?) { var users: [User] = [] let group = DispatchGroup() let serialQueue = DispatchQueue(label: "serialQueue") DatabaseProvider.shanetworkingInstance.usersDatabaseReference.observe(.value, with: { snapshot in guard let data = snapshot.value as? [String: AnyObject] else { return } for (_, value) in data { guard let values = value as? [String: AnyObject] else { return } guard let newUser = User(data: values) else { return } group.enter() newUser.fetchProfileImage(completionHandler: { (image) in serialQueue.async { newUser.profileImage = image users.append(newUser) group.leave() } }) } group.notify(queue: .main, execute: { completionHandler?(users) }) }) } func fetchAllChatrooms (completionHandler: chatroomsHandler?) { var chatrooms = [Chatroom]() let group = DispatchGroup() let serialQueue = DispatchQueue(label: "serialQueue") DatabaseProvider.shanetworkingInstance.chatroomsDatabaseReference.observe(.value, with: { snapshot in guard let data = snapshot.value as? [String: AnyObject] else { return } for (_, value) in data { guard let value = value as? [String: AnyObject] else { return } guard let newChatroom = Chatroom(data: value) else { return } group.enter() self.fetchChatroomUsers(chatroom: newChatroom, completionHandler: { (chatroom) in serialQueue.async { chatrooms.append(newChatroom) group.leave() } }) } group.notify(queue: .main, execute: { completionHandler?(Array(Set<Chatroom>(chatrooms))) }) }) } private func validateNewUsers(currentUser: User, users: [User], chatrooms: [Chatroom], completionHandler: usersCompletionHandler?) { let chatPartners = self.chatPartners(currentUser: currentUser, chatrooms: chatrooms) let validUsers = users .filter { currentUser.id != $0.id } .filter { currentUser.distanceFromUser(atLocation: $0.coordinates) <= 8046.72 } .filter { !chatPartners.contains($0.id) } completionHandler?(validUsers) } private func chatPartners (currentUser: User, chatrooms: [Chatroom]) -> Set<String> { var results = [String]() for chatroom in chatrooms { if currentUser.id == chatroom.firstUserId { results.append(chatroom.secondUserId) } else if currentUser.id == chatroom.secondUserId { results.append(chatroom.firstUserId) } } return Set(results) }