Como introducción, me gustaría recordar la cita del
tío BobEstás leyendo este artículo por dos razones. El primero, usted es un programador, el segundo, quiere ser el mejor programador.
Imagina que estás en una biblioteca y buscas algunos libros. Si la biblioteca está ordenada, tiene categorías de libros, encontrará rápidamente el que necesita. Además, el diseño interior y la arquitectura geniales harán que su estancia en esta biblioteca sea bastante cómoda para usted.
Al igual que con la escritura de libros, si desea crear algo grandioso, entonces necesita saber cómo escribir y cómo organizar su código. Si tiene miembros del equipo u otra persona que tiene su código (obsoleto), solo necesitan ver los nombres de las variables o paquetes o clases, y lo entenderán de inmediato. No necesitan decir "E ** l" I este código y comenzarlo de nuevo desde cero.
¿Qué es un código limpio?

TraducciónEstimado programador:
Cuando escribí este código, ¡solo Dios y yo sabíamos cómo funciona!
¡Ahora solo Dios lo sabe!
Antes de intentar optimizar esta rutina y no conducirá al éxito (muy probablemente), aumente el contador de tiempo para advertir al próximo desarrollador
Total de horas dedicadas: 567
Como puede ver, no es suficiente terminar el desarrollo más rápido. Si en el futuro no pueden resolver este código, también se convertirá en una deuda técnica.
Su código está en un estado "Puro" si todos los miembros de su equipo pueden entenderlo. Cualquier desarrollador que no sea el autor original puede leer y mejorar el código limpio. Con la comprensión viene la legibilidad, mutabilidad, extensibilidad y mantenibilidad.
¿Debo ocuparme de esto?
La razón por la que debería preocuparse por la limpieza de su código es porque describe sus pensamientos a otros desarrolladores. Es por eso que debe tener cuidado de que su código sea más elegante, simple y legible.
Señales de código limpio
- Tu código debe ser elegante: tu código debe hacerte sonreír como una caja de música bien hecha o un automóvil bien diseñado
- Su código debe estar enfocado: cada función, cada clase, cada módulo implementa una tarea, que permanece completamente no distraída y no contaminada por los detalles circundantes.
- El código no contiene duplicados
- Pase todas las pruebas con éxito
- Minimizó el número de entidades, métodos, clases, etc.
La diferencia entre un buen programador y un profesional es que un programador profesional comprende que la comprensión del código es primordial. Un profesional usa este poder para escribir código que todos entienden - Robert C. Martin
Escribe los nombres conscientes
Elegir un buen nombre puede llevar mucho tiempo, pero luego ahorrará más. El nombre de una variable, función, clase debería responder a todas las preguntas importantes. Debería decirle por qué existe, por qué es necesario y cómo usarlo. Si el nombre requiere comentario, el nombre no revela su propósito
Ejemplo simple
Nombres de clase
Las clases y los objetos deben ser sustantivos, como Custom, WikiPage, Account y AddressParser. Evite palabras como Administrador, Procesador, Datos o Información. También recuerde que el nombre de la clase no debe ser un verbo.
Nombres de métodos
Los nombres de los métodos deben ser verbos, por ejemplo postPayment, deletePage o save. Modificadores de acceso, los predicados deben nombrarse por su valor y con el prefijo get, set y de acuerdo con el estándar JavaBean.
Antes de continuar, tome un breve descanso, abastecerse de café y galletas.

Bien, ahora pasemos a los principios SÓLIDOS.
Escribir código que se adhiera a los principios de SOLID
Estos principios fueron desarrollados por el tío Bob, SOLID es una abreviatura que describe un conjunto de principios diseñados para escribir un buen código.
Principio de responsabilidad única (S)
Esto significa que cada clase debe tener una sola responsabilidad. Nunca debe haber más de una razón para cambiar una clase. No es necesario agregar todo a tu clase, simplemente porque puedes hacerlo. Divide las clases grandes en clases más pequeñas y evita las clases de Dios.
Un ejemplo:
Tenemos un RecyclerView.Adapter con lógica de negocios dentro de onBindViewHolder
class MyAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] val status = if(friend.maritalStatus == "Married") { "Sold out" } else { "Available" } holder.name.text = friend.name holder.popText.text = friend.email holder.status.text = status } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } }
Esto hace que RecyclerView.Adapter no sea el único responsable porque contiene lógica de negocios dentro de onBindViewHolder. Este método solo es responsable de insertar datos en la vista.
El principio de apertura / cierre (O)
Las entidades de software deben estar abiertas para expansión, pero cerradas para modificación. Esto significa que si está desarrollando la clase A y sus colegas querrán cambiar la función dentro de esta clase. Pueden hacerlo fácilmente expandiendo esta clase sin cambiar la clase misma.
Un ejemplo simple es la clase RecyclerView.Adapter. Puede expandirlo fácilmente y crear su propio adaptador con un comportamiento no estándar sin modificar el RecyclerView.Adapter.
class FriendListAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] holder.name.text = friend.name holder.popText.text = friend.email } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } }
El principio de sustitución de Barbara Lisk (L)
La clase secundaria debe complementar al padre y no cambiarlo. Esto significa que la subclase debe anular los métodos principales que no violan la funcionalidad de esta clase principal. Por ejemplo, creamos una interfaz de clase que tiene un oyente onClick () y luego aplica el oyente en MyActivity y le da una acción Toast cuando se llama a onClick ().
interface ClickListener { fun onClick() } class MyActivity: AppCompatActivity(), ClickListener {
Principio de separación de interfaz
Este principio establece que el cliente no debe depender de métodos que no utiliza.
Esto significa que si desea escribir la clase A y agregarle la funcionalidad de otra clase B. No es necesario redefinir todas las clases A dentro de la clase B.
Ejemplo: en nuestra actividad, necesitamos implementar SearchView.OnQueryTextListener (), pero solo necesitamos el método onQuerySubmit ().
mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean {
¿Cómo hacemos esto? Fácil! Simplemente cree una devolución de llamada y una clase que extienda SearchView.OnQueryTextListener ()
interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } class SearchViewQueryTextListener(val callback: SearchViewQueryTextCallback): SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } }
Y así lo agregamos a nuestra vista
val listener = SearchViewQueryTextListener( object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) {
O así usando la función de extensión en Kotlin
interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } fun SearchView.setupQueryTextSubmit (callback: SearchViewQueryTextCallback) { setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } }) }
val listener = object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) {
Principio de inversión de dependencia
Dependencia de abstracciones, sin dependencia de algo específico.
La definición de inversión de dependencia del tío Bob consta de dos conceptos.
Los módulos de nivel superior no deben depender de los módulos de nivel inferior. Ambos deben estar vinculados a las abstracciones. Las abstracciones no deberían depender de los detalles. Los detalles deben depender de las abstracciones. Los módulos de alto nivel que implementan una lógica compleja deberían ser fácilmente reutilizables sin cambios en los módulos de nivel inferior. Para hacer esto, debe ingresar una abstracción que separe los módulos de los niveles superior e inferior entre sí.
Un ejemplo simple de este patrón MVP. Tiene un objeto de interfaz que lo ayuda a comunicarse con clases específicas. Qué se entiende: las clases de IU (Actividad / Fragmento) no necesitan conocer la implementación real de los métodos del presentador. Por lo tanto, si realiza cambios dentro del presentador, las clases de IU no tienen que preocuparse por estos cambios.
Veamos un ejemplo.
interface UserActionListener { fun getUserData() } class UserPresenter : UserActionListener() {
Y ahora en la actividad
class UserActivity : AppCompatActivity() {
De esta manera, creamos una interfaz que abstrae la implementación del presentador, y nuestra clase de vista mantiene una referencia a PresenterInterface.