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 código. Um curriculo diz o que você afirma saber. Um portfolio prova o que você 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 não 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 único projeto bem feito impressiona mais que dez projetos meia-boca.
Projeto 1: App Android Completo
Este é o projeto obrigatório 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 você vai além 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 técnica:
// Exemplo: DSL para validação
// Mostra conhecimento avançado 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 Código
Recrutadores olham não apenas se o código funciona, mas como ele e escrito. Siga estas práticas:
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 paginação 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 código de outros
Testes: O Diferencial
A maioria dos portfolios não 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
- Código 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 documentação: Código sem README parece abandonado
Cronograma Sugerido
Se você 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 documentação
- Semana 8: Revisao final e inicio das candidaturas
Conclusão
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 código 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. Ter projetos em múltiplas linguagens como Go ou Python demonstra versatilidade e amplia suas oportunidades. Cada melhoria e um investimento na sua carreira como desenvolvedor Kotlin.