askill
coding-standards

coding-standardsSafety 90Repository

Estandares de codigo para C# .NET 8 y TypeScript/React

0 stars
1.2k downloads
Updated 2/2/2026

Package Files

Loading files...
SKILL.md

Coding Standards

C# / .NET 8 Standards

Naming Conventions

ElementConventionExample
NamespacePascalCaseMyApp.Services
Class/RecordPascalCaseUserService
InterfaceIPascalCaseIUserRepository
MethodPascalCaseGetUserById
PropertyPascalCaseFirstName
Private field_camelCase_userRepository
ParametercamelCaseuserId
Local variablecamelCaseuserCount
ConstantPascalCaseMaxRetries
EnumPascalCaseUserStatus.Active

File Organization

// 1. Usings (ordenados, sin aliases innecesarios)
using System;
using Microsoft.Extensions.Logging;
using MyApp.Domain.Entities;

// 2. Namespace (file-scoped)
namespace MyApp.Application.Services;

// 3. Tipo principal
public class UserService : IUserService
{
    // 4. Campos privados
    private readonly IUserRepository _repository;
    private readonly ILogger<UserService> _logger;

    // 5. Constructor
    public UserService(IUserRepository repository, ILogger<UserService> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    // 6. Propiedades publicas

    // 7. Metodos publicos

    // 8. Metodos privados
}

Modern C# Features (.NET 8)

// Records para DTOs inmutables
public record UserDto(Guid Id, string Email, string Name);

// Primary constructors (C# 12)
public class UserService(IUserRepository repository, ILogger<UserService> logger)
{
    public async Task<User?> GetByIdAsync(Guid id) =>
        await repository.GetByIdAsync(id);
}

// Pattern matching
var message = user switch
{
    { IsAdmin: true } => "Welcome, Admin!",
    { IsActive: false } => "Account inactive",
    { Name: var name } => $"Hello, {name}"
};

// Collection expressions
int[] numbers = [1, 2, 3, 4, 5];
List<string> names = ["Alice", "Bob", "Charlie"];

// Nullable reference types
public User? FindUser(string email) // Puede ser null
public User GetUser(Guid id)        // Nunca null (throws si no existe)

// Raw string literals
var json = """
    {
        "name": "John",
        "email": "john@example.com"
    }
    """;

Async/Await

// BIEN: Async todo el camino
public async Task<User> GetUserAsync(Guid id, CancellationToken ct = default)
{
    return await _repository.GetByIdAsync(id, ct)
        ?? throw new NotFoundException($"User {id} not found");
}

// BIEN: ConfigureAwait en libraries
public async Task<User> GetUserAsync(Guid id)
{
    return await _repository.GetByIdAsync(id).ConfigureAwait(false);
}

// MAL: Blocking async
public User GetUser(Guid id)
{
    return _repository.GetByIdAsync(id).Result; // Deadlock potential!
}

// MAL: async void (excepto event handlers)
public async void ProcessUser(User user) { } // NO!

Error Handling

// Custom exceptions
public class NotFoundException : Exception
{
    public NotFoundException(string message) : base(message) { }
}

public class ValidationException : Exception
{
    public IReadOnlyList<ValidationError> Errors { get; }

    public ValidationException(IEnumerable<ValidationError> errors)
        : base("Validation failed")
    {
        Errors = errors.ToList();
    }
}

// Result pattern (no exceptions para flujo normal)
public async Task<Result<User>> GetUserAsync(Guid id)
{
    var user = await _repository.GetByIdAsync(id);
    if (user is null)
        return Result.Failure<User>(UserErrors.NotFound(id));

    return Result.Success(user);
}

LINQ Best Practices

// BIEN: Encadenar queries
var activeAdmins = users
    .Where(u => u.IsActive)
    .Where(u => u.Role == Role.Admin)
    .OrderBy(u => u.Name)
    .ToList();

// BIEN: Proyeccion para solo campos necesarios
var emails = users.Select(u => u.Email).ToList();

// MAL: Multiple enumerations
var count = users.Count(); // Enumera
var first = users.First(); // Enumera de nuevo

// BIEN: Materializar primero si se usa multiples veces
var usersList = users.ToList();
var count = usersList.Count;
var first = usersList.First();

TypeScript / React Standards

Naming Conventions

ElementConventionExample
File (component)PascalCaseUserCard.tsx
File (util/hook)kebab-caseuse-user.ts
ComponentPascalCaseUserCard
HookcamelCase (use-)useUser
FunctioncamelCaseformatDate
VariablecamelCaseuserName
ConstantUPPER_SNAKEMAX_RETRIES
Interface/TypePascalCaseUserProps
EnumPascalCaseUserStatus.Active

File Organization

// 1. Imports (externos, internos, estilos)
import { useState, useEffect } from 'react';
import { User } from '@/types';
import { formatDate } from '@/lib/utils';
import styles from './user-card.module.css';

// 2. Types/Interfaces
interface UserCardProps {
  user: User;
  onSelect?: (id: string) => void;
}

// 3. Component
export function UserCard({ user, onSelect }: UserCardProps) {
  // a. Hooks
  const [isExpanded, setIsExpanded] = useState(false);

  // b. Derived state
  const fullName = `${user.firstName} ${user.lastName}`;

  // c. Effects
  useEffect(() => {
    // ...
  }, []);

  // d. Handlers
  const handleClick = () => {
    onSelect?.(user.id);
  };

  // e. Render
  return (
    <div className={styles.card} onClick={handleClick}>
      <h3>{fullName}</h3>
      <p>{user.email}</p>
    </div>
  );
}

TypeScript Best Practices

// Tipos estrictos
interface User {
  id: string;
  email: string;
  name: string;
  role: 'admin' | 'user' | 'guest'; // Union types
  createdAt: Date;
}

// Generics
function first<T>(array: T[]): T | undefined {
  return array[0];
}

// Type guards
function isAdmin(user: User): user is User & { role: 'admin' } {
  return user.role === 'admin';
}

// Utility types
type PartialUser = Partial<User>;           // Todo opcional
type RequiredUser = Required<User>;          // Todo requerido
type UserWithoutId = Omit<User, 'id'>;       // Sin id
type UserKeys = keyof User;                   // 'id' | 'email' | ...

// No usar any
function process(data: unknown) {            // BIEN
  if (typeof data === 'string') {
    return data.toUpperCase();
  }
}

function process(data: any) { }              // MAL

React Best Practices

// Props con destructuring
function UserCard({ user, onSelect }: UserCardProps) {
  // ...
}

// Default props
function Button({ variant = 'primary', ...props }: ButtonProps) {
  // ...
}

// Avoid inline functions in render
// MAL
<button onClick={() => handleClick(id)}>Click</button>

// BIEN
const handleButtonClick = useCallback(() => {
  handleClick(id);
}, [id, handleClick]);

<button onClick={handleButtonClick}>Click</button>

// Conditional rendering
{isLoading && <Spinner />}
{error ? <Error message={error} /> : <Content />}
{items.length > 0 && <List items={items} />}

// Fragment shorthand
<>
  <Header />
  <Main />
</>

Reglas Comunes

Tamano de Archivos

  • Tipico: 200-400 lineas
  • Maximo: 800 lineas
  • Si excede, dividir en modulos mas pequenos

Complejidad

  • Metodos/funciones: max 20-30 lineas
  • Parametros: max 4-5
  • Anidamiento: max 3 niveles

Comentarios

// BIEN: Explicar el "por que", no el "que"
// Usamos retry porque el servicio externo es inestable
await RetryAsync(() => ExternalService.CallAsync());

// MAL: Comentar lo obvio
// Incrementa el contador
counter++;

// BIEN: TODO con contexto
// TODO(issue-123): Implementar paginacion

Imports/Usings

  • Ordenar alfabeticamente
  • Agrupar por tipo (framework, third-party, local)
  • Remover no usados

Git Commits

<type>: <description>

Types: feat, fix, refactor, docs, test, chore, perf, ci

Examples:
feat: add user registration endpoint
fix: resolve null reference in UserService
refactor: extract email validation to separate class
test: add unit tests for CreateUserHandler

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

92/100Analyzed 2/10/2026

A high-quality technical reference for C# and React development, providing clear naming conventions, file organization patterns, and modern language features with actionable examples.

90
95
90
95
90

Metadata

Licenseunknown
Version-
Updated2/2/2026
Publisherroberflo

Tags

ci-cdobservabilitytesting