Arquitetura limpa no contexto do desenvolvimento de plataforma cruzada

Olá pessoal. Recentemente, alguns artigos foram escritos sobre o tema da arquitetura limpa. Ou seja, uma arquitetura limpa que permite escrever aplicativos convenientes para manutenção e teste. Você pode ler sobre a arquitetura pura em si mesmo em artigos maravilhosos como: Conceitos errôneos de arquitetura limpa ou arquitetura limpa ; portanto, não vejo razão para repetir o que já foi escrito.

Para começar, deixe-me me apresentar, meu nome é Kakushev Rasul. Aconteceu que eu estava simultaneamente envolvido no desenvolvimento nativo no ios e no android, bem como no desenvolvimento de código de back-end para aplicativos móveis na Navibit. Ainda é uma empresa pouco conhecida, que está se preparando para entrar no mercado para a venda de materiais de construção. Temos uma equipe muito pequena e, portanto, o desenvolvimento de aplicativos móveis cabe inteiramente aos meus ombros (ainda não muito profissionais).

No meu trabalho, muitas vezes tenho que fazer um aplicativo no ios e no android e, como você entende, devido a diferenças nas plataformas, muitas vezes preciso escrever a mesma funcionalidade várias vezes. Demora muito tempo e, há algum tempo, quando conheci uma arquitetura limpa, tive a seguinte idéia: as linguagens kotlin e swift são bastante semelhantes, mas as plataformas são diferentes, mas na arquitetura limpa há uma camada de domínio que não está ligada à plataforma , mas contém lógica de negócios pura. O que acontecerá se você pegar toda a camada de domínio do Android e transferi-la para o iOS, com alterações mínimas?

Bem, concebido - feito. Comecei a transferência. E, de fato, a ideia acabou sendo verdadeira. Julgue por si mesmo. Por exemplo, aqui está um interator no kotlin e swift:

Kotlin (Android)

class AuthInteractor @Inject internal constructor(private val authRepository: AuthRepository, private val profileRepository: ProfileRepository) { fun auth(login: String, password: String, cityId: Int): Single<Auth> = authRepository.auth(login.trim { it <= ' ' }, password.trim { it <= ' ' }, cityId, cloudToken) fun restore(login: String, password: String, cityId: Int, confirmHash: String): Single<AuthInfo> = authRepository.restore(login.trim { it <= ' ' }, password.trim { it <= ' ' }, cityId, confirmHash) fun restore(password: String, confirmHash: String): Single<AuthInfo> = authRepository.restore(password.trim { it <= ' ' }, confirmHash) fun getToken(): String = authRepository.checkIsAuth() fun register(login: String, family: String, name: String, password: String, cityId: Int, confirmHash: String): Single<AuthInfo> = authRepository.register(login.trim { it <= ' ' }, family.trim { it <= ' ' }, name.trim { it <= ' ' }, password.trim { it <= ' ' }, cityId, confirmHash) fun checkLoginAvailable(login: String): Single<LoginAvailable> = authRepository.checkLoginAvailable(login) fun saveTempCityInfo(authCityInfo: AuthCityInfo?) = authRepository.saveTempCityInfo(authCityInfo) fun checkPassword(password: String): Single<AuthInfo> = authRepository.checkPassword(password) fun auth(auth: Auth) { authRepository.saveToken(auth.token!!) profileRepository.saveProfile(auth.name!!, auth.phone!!, auth.location!!) } companion object { const val AUTH_ERROR = "HTTP 401 Unauthorized" } } 

Swift (iOS):

 class AuthInteractor { public static let AUTH_ERROR = "HTTP 401 Unauthorized" private let authRepository: AuthRepository private let profileRepository: ProfileRepository private let cloudMessagingRepository: CloudMessagingRepository init(authRepository: AuthRepository, profileRepository: ProfileRepository, cloudMessagingRepository: CloudMessagingRepository) { self.authRepository = authRepository self.profileRepository = profileRepository self.cloudMessagingRepository = cloudMessagingRepository } func auth(login: String, password: String, cityId: Int) -> Observable<Auth> { return authRepository.auth(login: login.trim(), password: password.trim(), cityId: cityId, cloudMessagingToken: cloudMessagingRepository.getCloudToken()) } func restore(login: String, password: String, cityId: Int, confirmHash: String) -> Observable<AuthInfo> { return authRepository.restore(login: login.trim(), password: password.trim(), cityId: cityId, confirmHash: confirmHash) } func restore(password: String, confirmHash: String) -> Observable<AuthInfo> { return authRepository.restore(password: password.trim(), confirmHash: confirmHash) } func getToken() -> String { return authRepository.checkIsAuth() } func register(login: String, family: String, name: String, password: String, cityId: Int, confirmHash: String) -> Observable<AuthInfo> { return authRepository.register(login: login.trim(), family: family.trim(), name: name.trim(), password: password.trim(), cityId: cityId, confirmHash: confirmHash) } func checkLoginAvailable(login: String) -> Observable<LoginAvailable> { return authRepository.checkLoginAvailable(login: login) } func saveTempCityInfo(authCityInfo: AuthCityInfo?) { authRepository.saveTempCityInfo(authCityInfo: authCityInfo) } func checkPassword(password: String) -> Observable<AuthInfo> { return authRepository.checkPassword(password: password) } func auth(auth: Auth) { authRepository.saveToken(token: auth.token) profileRepository.saveProfile(name: auth.name, phone: auth.phone, location: auth.location) } } 

Ou aqui está um exemplo de como são as interfaces do repositório em diferentes plataformas:

Kotlin (Android)

 interface AuthRepository { fun auth(login: String, password: String, cityId: Int, cloudMessagingToken: String): Single<Auth> fun register(login: String, family: String, name: String, password: String, cityId: Int, confirmHash: String): Single<AuthInfo> fun restore(login: String, password: String, cityId: Int, confirmHash: String): Single<AuthInfo> fun restore(password: String, confirmHash: String): Single<AuthInfo> fun checkLoginAvailable(login: String): Single<LoginAvailable> fun sendCode(login: String): Single<CodeCheck> fun checkCode(hash: String, code: String): Single<CodeConfirm> fun checkIsAuth(): String fun saveToken(token: String) fun removeToken() fun notifyConfirmHashListener(confirmHash: String) fun getResendTimer(time: Long): Observable<Long> fun checkPassword(password: String): Single<AuthInfo> fun saveTempCityInfo(authCityInfo: AuthCityInfo?) fun saveTempConfirmInfo(codeConfirmInfo: CodeConfirmInfo) fun getTempCityInfo(): AuthCityInfo? fun getConfirmHashListener(): Observable<String> fun getTempConfirmInfo(): CodeConfirmInfo? } 

Swift (iOS):

 protocol AuthRepository { func auth(login: String, password: String, cityId: Int, cloudMessagingToken: String) -> Observable<Auth> func register(login: String, family: String, name: String, password: String, cityId: Int, confirmHash: String) -> Observable<AuthInfo> func restore(login: String, password: String, cityId: Int, confirmHash: String) -> Observable<AuthInfo> func restore(password: String, confirmHash: String) -> Observable<AuthInfo> func checkLoginAvailable(login: String) -> Observable<LoginAvailable> func sendCode(login: String) -> Observable<CodeCheck> func checkCode(hash: String, code: String) -> Observable<CodeConfirm> func checkIsAuth() ->String func saveToken(token: String) func removeToken() func notifyConfirmHashListener(confirmHash: String) func getResendTimer(time: Int) -> Observable<Int> func checkPassword(password: String) -> Observable<AuthInfo> func saveTempCityInfo(authCityInfo: AuthCityInfo?) func saveTempConfirmInfo(codeConfirmInfo: CodeConfirmInfo) func getTempCityInfo() -> AuthCityInfo? func getConfirmHashListener() -> Observable<String> func getTempConfirmInfo() -> CodeConfirmInfo? } 

A situação é semelhante à camada de apresentação, pois os apresentadores e as interfaces de exibição nas duas plataformas são iguais. Portanto, graças a essa transferência, minha velocidade de desenvolvimento quase dobrou, porque, devido ao fato de as camadas de domínio e apresentação já estarem totalmente formadas nas duas plataformas, a única coisa que resta é conectar bibliotecas específicas e modificar as camadas de interface do usuário e dados.

Obrigado por ler até o fim. Espero que este artigo beneficie desenvolvedores de dispositivos móveis envolvidos no desenvolvimento nativo. Tudo de bom.

Source: https://habr.com/ru/post/pt419173/


All Articles