Um portfolio bem construido pode ser o diferencial entre receber uma proposta de emprego ou ser ignorado. Para desenvolvedores Kotlin, ter projetos que demonstram suas habilidades de forma clara e organizada e fundamental. Neste guia, vou te mostrar exatamente como montar um portfolio que se destaca.
Por Que Portfolio Importa Mais Que Curriculo
No mundo de desenvolvimento, recrutadores e tech leads querem ver codigo. Um curriculo diz o que voce afirma saber. Um portfolio prova o que voce realmente sabe fazer.
Empresas como Nubank, iFood e PicPay frequentemente pedem acesso ao GitHub do candidato antes mesmo de agendar uma entrevista. Ter projetos bem organizados la pode abrir portas que um curriculo sozinho nao abre.
Estrutura de um Portfolio Eficaz
Um portfolio de desenvolvedor Kotlin deve ter entre 3 e 5 projetos de qualidade. Qualidade importa muito mais que quantidade. Um unico projeto bem feito impressiona mais que dez projetos meia-boca.
Projeto 1: App Android Completo
Este e o projeto obrigatorio para quem quer vagas Android. Deve demonstrar:
// Arquitetura limpa com MVVM
// domain/usecase/GetProductsUseCase.kt
class GetProductsUseCase(
private val repository: ProductRepository
) {
operator fun invoke(
category: String? = null,
sortBy: SortOption = SortOption.NAME
): Flow<Result<List<Product>>> {
return repository.getProducts()
.map { result ->
result.map { products ->
products
.let { list ->
if (category != null) {
list.filter { it.category == category }
} else list
}
.sortedWith(sortBy.comparator)
}
}
}
}
// presentation/viewmodel/ProductListViewModel.kt
@HiltViewModel
class ProductListViewModel @Inject constructor(
private val getProducts: GetProductsUseCase,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
private val _uiState = MutableStateFlow(ProductListUiState())
val uiState: StateFlow<ProductListUiState> = _uiState.asStateFlow()
private val selectedCategory = savedStateHandle.getStateFlow<String?>(
"category", null
)
init {
viewModelScope.launch {
selectedCategory.flatMapLatest { category ->
getProducts(category = category)
}.collect { result ->
result
.onSuccess { products ->
_uiState.update {
it.copy(products = products, loading = false)
}
}
.onFailure { error ->
_uiState.update {
it.copy(error = error.message, loading = false)
}
}
}
}
}
}
O app deve consumir uma API publica (como PokeAPI, TMDB ou OpenWeather), ter persistencia local, tratamento de erros e uma UI bem construida com Jetpack Compose.
Projeto 2: API Backend com Kotlin
Mostra que voce vai alem do mobile:
// API REST com Spring Boot
// Estrutura bem organizada
@RestController
@RequestMapping("/api/v1/bookmarks")
class BookmarkController(
private val bookmarkService: BookmarkService
) {
@GetMapping
suspend fun list(
@AuthenticationPrincipal user: UserPrincipal,
@RequestParam(defaultValue = "0") page: Int,
@RequestParam(defaultValue = "20") size: Int
): ResponseEntity<PagedResponse<BookmarkDTO>> {
val bookmarks = bookmarkService.listByUser(user.id, page, size)
return ResponseEntity.ok(bookmarks)
}
@PostMapping
suspend fun create(
@AuthenticationPrincipal user: UserPrincipal,
@Valid @RequestBody request: CreateBookmarkRequest
): ResponseEntity<BookmarkDTO> {
val bookmark = bookmarkService.create(user.id, request)
return ResponseEntity.status(HttpStatus.CREATED).body(bookmark)
}
@DeleteMapping("/{id}")
suspend fun delete(
@AuthenticationPrincipal user: UserPrincipal,
@PathVariable id: String
): ResponseEntity<Unit> {
bookmarkService.delete(user.id, id)
return ResponseEntity.noContent().build()
}
}
// Testes - Fundamental para impressionar
@SpringBootTest
@AutoConfigureMockMvc
class BookmarkControllerTest {
@Autowired
private lateinit var mockMvc: MockMvc
@MockkBean
private lateinit var bookmarkService: BookmarkService
@Test
fun `should return paginated bookmarks`() {
val bookmarks = listOf(
createBookmarkDTO(id = "1", title = "Kotlin Blog"),
createBookmarkDTO(id = "2", title = "Spring Docs")
)
coEvery { bookmarkService.listByUser(any(), any(), any()) } returns
PagedResponse(bookmarks, total = 2, page = 0, size = 20)
mockMvc.get("/api/v1/bookmarks") {
header("Authorization", "Bearer ${generateTestToken()}")
}.andExpect {
status { isOk() }
jsonPath("$.content") { isArray() }
jsonPath("$.content.length()") { value(2) }
jsonPath("$.total") { value(2) }
}
}
}
Projeto 3: Biblioteca ou Ferramenta
Criar uma biblioteca ou CLI mostra maturidade tecnica:
// Exemplo: DSL para validacao
// Mostra conhecimento avancado de Kotlin
class ValidationBuilder<T> {
private val rules = mutableListOf<ValidationRule<T>>()
fun field(
name: String,
extractor: (T) -> Any?,
block: FieldValidationBuilder.() -> Unit
) {
val fieldBuilder = FieldValidationBuilder(name, extractor)
fieldBuilder.block()
rules.addAll(fieldBuilder.build())
}
fun validate(obj: T): ValidationResult {
val errors = rules.mapNotNull { rule ->
rule.validate(obj)
}
return if (errors.isEmpty()) {
ValidationResult.Valid
} else {
ValidationResult.Invalid(errors)
}
}
}
// Uso da DSL
val userValidator = validator<User> {
field("nome", { it.nome }) {
notBlank()
minLength(2)
maxLength(100)
}
field("email", { it.email }) {
notBlank()
matchesPattern(EMAIL_REGEX)
}
field("idade", { it.idade }) {
min(18)
max(120)
}
}
val resultado = userValidator.validate(user)
when (resultado) {
is ValidationResult.Valid -> salvarUsuario(user)
is ValidationResult.Invalid -> mostrarErros(resultado.errors)
}
Qualidade do Codigo
Recrutadores olham nao apenas se o codigo funciona, mas como ele e escrito. Siga estas praticas:
Nomenclatura Clara
// Ruim
fun proc(d: List<Int>): Int = d.filter { it > 0 }.sum()
// Bom
fun calcularSomaPositivos(valores: List<Int>): Int {
return valores
.filter { it > 0 }
.sum()
}
Commit Messages Significativas
Seus commits contam uma historia. Em vez de “fix bug” ou “update code”, escreva:
- “Adiciona paginacao na listagem de produtos”
- “Corrige tratamento de erro quando API retorna 404”
- “Refatora ViewModel para usar StateFlow em vez de LiveData”
README Bem Escrito
Cada projeto deve ter um README que explica:
- O que o projeto faz
- Tecnologias utilizadas
- Como rodar localmente
- Screenshots ou GIFs (para apps visuais)
- Decisoes arquiteturais e por que foram tomadas
Organizacao do GitHub
Perfil Profissional
Configure seu perfil do GitHub com:
- Foto profissional
- Bio clara mencionando Kotlin
- Link para LinkedIn
- Projetos pinados (os melhores no topo)
Contribuicoes Regulares
O grafico de contribuicoes do GitHub mostra consistencia. Tente:
- Fazer commits regularmente (mesmo pequenos)
- Abrir issues e PRs em projetos open source
- Revisar codigo de outros
Testes: O Diferencial
A maioria dos portfolios nao tem testes. Ter testes bem escritos e um diferencial enorme:
// Testes de ViewModel com coroutines
class ProductViewModelTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
private val repository = FakeProductRepository()
private lateinit var viewModel: ProductViewModel
@Before
fun setup() {
viewModel = ProductViewModel(GetProductsUseCase(repository))
}
@Test
fun `loading state should be true initially`() = runTest {
val states = mutableListOf<ProductListUiState>()
val job = launch {
viewModel.uiState.toList(states)
}
advanceUntilIdle()
assertThat(states.first().loading).isTrue()
assertThat(states.last().loading).isFalse()
assertThat(states.last().products).isNotEmpty()
job.cancel()
}
}
Erros Comuns a Evitar
- Projetos incompletos: Melhor ter 3 projetos terminados do que 10 pela metade
- Codigo copiado de tutoriais: Recrutadores percebem. Adicione suas proprias features
- Sem tratamento de erros: Apps que crasham causam pessima impressao
- Sem .gitignore: Nunca commite arquivos de build, IDE ou credenciais
- Falta de documentacao: Codigo sem README parece abandonado
Cronograma Sugerido
Se voce esta comecando do zero, siga este cronograma:
- Semanas 1-3: Projeto Android completo
- Semanas 4-5: Projeto backend com API
- Semana 6: Projeto biblioteca/ferramenta
- Semana 7: Polimento, testes e documentacao
- Semana 8: Revisao final e inicio das candidaturas
Conclusao
Montar um portfolio solido requer dedicacao, mas o retorno e enorme. Projetos bem feitos demonstram suas habilidades de forma que nenhum curriculo consegue. Foque em qualidade, mantenha o codigo organizado, escreva testes e documente suas decisoes.
Lembre-se: o portfolio e um documento vivo. Continue melhorando seus projetos, adicionando features e aprendendo novas tecnologias. Cada melhoria e um investimento na sua carreira como desenvolvedor Kotlin.