用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/navikt/helved-utbetaling --skill readable-code命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | readable-code |
| description | Write readable and maintainable code following helved-utbetaling patterns |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"ai-assistant","language":"kotlin","framework":"ktor","domain":"nav-payment-system"} |
I guide you to write readable and maintainable Kotlin code that follows the established patterns in the helved-utbetaling codebase.
Load this skill when you are writing, refactoring, or reviewing code in this project.
Prerequisites: Root
AGENTS.mdcovers naming conventions, error handling patterns, testing patterns, and architecture. This skill provides concrete code examples that complement those rules.
Target 10-30 lines per function. Use early returns for clarity. Extract complex logic into helper functions.
// Good: Clear flow, early returns, focused logic
fun branntaarn(
config: Config = Config(),
now: LocalDateTime = LocalDateTime.now(),
) {
if (now.toLocalDate().erHelligdag() || now.hour < 6 || now.hour > 21) return
val peisschtappern = PeisschtappernClient(config)
val slack = SlackClient(config)
val branner = peisschtappern.branner()
.filter { brann -> brann.timeout.isBefore(now) }
if (branner.isEmpty()) return
val grouped = branner.groupBy { it.fagsystem }
slack.postAggregated(grouped)
branner.forEach(peisschtappern::slukk)
}
// Bad: Nested conditions, unclear flow
fun branntaarn(
config: Config = Config(),
now: LocalDateTime = LocalDateTime.now(),
) {
if (!now.toLocalDate().erHelligdag() && now.hour >= 6 && now.hour <= 21) {
val peisschtappern = PeisschtappernClient(config)
val slack = SlackClient(config)
val branner = peisschtappern.branner().filter { it.timeout.isBefore(now) }
if (branner.isNotEmpty()) {
val grouped = branner.groupBy { it.fagsystem }
slack.postAggregated(grouped)
for (brann in branner) {
peisschtappern.slukk(brann)
}
}
}
}
Public API at the top, private helpers below. Group related functions together.
// Public API first, private helpers below
package branntaarn
class SlackClient(
private val config: Config,
private val client: HttpClient = HttpClientFactory.new(LogLevel.ALL),
) {
fun postAggregated(grouped: Map<String, List<Brann>>) {
runBlocking {
client.post(config.slack.host.toString()) {
contentType(ContentType.Application.Json)
setBody(jsonAggregated(grouped, config))
}
}
}
}
private fun jsonAggregated(
grouped: Map<String, List<Brann>>,
config: Config
): String { /* ... */ }
private fun emoji(config: Config): String = when (config.nais.cluster) {
"prod-gcp" -> ":fire:"
else -> ""
}
Keep transformation pipelines readable with chained operations.
// Good: Clear transformation pipeline
val sakIdText = if (sakIds.size <= displayLimit) {
sakIds.joinToString(", ")
} else {
val shown = sakIds.take(displayLimit).joinToString(", ")
val remaining = sakIds.size - displayLimit
"$shown _(+$remaining more not shown)_"
}
Use comments to explain WHY, not WHAT. Document business rules and non-obvious Norwegian terms.
// Good: Explains business rule
// Skip alerts outside operational hours (06-21, weekdays only, excluding holidays)
if (now.toLocalDate().erHelligdag() || now.hour < 6 || now.hour > 21) return
// Good: Clarifies Norwegian term
// Slukk (extinguish) - Delete the timer from peisschtappern
branner.forEach(peisschtappern::slukk)
Prefer self-documenting code over comments:
// Good: Self-documenting with named boolean
val isOutsideOperationalHours = now.toLocalDate().erHelligdag()
|| now.hour < 6
|| now.hour > 21
if (isOutsideOperationalHours) return
if (sakId.isEmpty()) {
badRequest("sakId cannot be empty", DocumentedErrors.INVALID_SAK_ID)
}
val utbetaling = dao.findById(utbetalingId)
?: notFound("Utbetaling $utbetalingId not found")
val result = Result.catch {
oppdragMapper.readValue(value)
}.onFailure { error ->
appLog.warn("Failed to parse oppdrag: ${error.message}")
}
// Good: Explicit null handling with logging
val oppdrag = oppdragMapper.readValue(value) ?: run {
appLog.warn("Failed to parse oppdrag for key $key")
return stopTimer(key)
}
// Bad: Silent failure
val oppdrag = oppdragMapper.readValue(value) ?: return
Constructor injection with default parameters. No DI framework. Wire in app entry point.
// Good: Clear dependencies, testable with defaults
class SlackClient(
private val config: Config,
private val client: HttpClient = HttpClientFactory.new(LogLevel.ALL),
) { /* ... */ }
// Good: App wiring in entry point
fun Application.utsjekk() {
val config = Config()
val datasource = Jdbc.initialize(config.jdbc)
val oppdragProducer = OppdragProducer(config.kafka)
val iverksettingService = IverksettingService(datasource, oppdragProducer)
routing {
iverksettingRoutes(iverksettingService)
}
}
// Bad: Hidden dependencies, hard to test
class SlackClient {
private val config = Config() // Hard to test
private val client = HttpClient(CIO) // Can't mock
}
data class Brann(
val key: String,
val timeout: LocalDateTime,
val sakId: String,
val fagsystem: String,
)
data class Config(
val azure: AzureConfig = AzureConfig(),
val slack: SlackConfig = SlackConfig(),
val nais: NaisConfig = NaisConfig(),
)
private fun emoji(config: Config): String = when (config.nais.cluster) {
"prod-gcp" -> ":fire:"
else -> ""
}
fun shouldSkipProcessing(now: LocalDateTime): Boolean =
now.toLocalDate().erHelligdag()
|| now.hour < 6
|| now.hour > 21
// Good: Functional chaining
val grouped = branner
.filter { brann -> brann.timeout.isBefore(now) }
.groupBy { it.fagsystem }
// Good: buildList for construction
val blocks = buildList {
add("""{"type": "header"}""")
grouped.entries.sortedBy { it.key }.forEach { (fagsystem, branner) ->
add("""{"type": "section", "text": "$fagsystem - ${branner.size}"}""")
}
}
// Good: String templates
val message = "*$totalCount missing kvitteringer across $fagsystemCount fagsystems*"
// Good: Triple-quoted string with trimIndent
val json = """
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Branntaarn Alert (${config.nais.cluster})"
}
}
""".trimIndent()