Распространенные ошибки и антипаттерны
❌ Антипаттерн 1: shared как свалка доменного кода
FORBIDDEN: Размещать доменную логику в shared/
// ❌ Плохо - доменная логика в shared
// shared/lib/article-helpers.ts
export function getArticleUrl(article: Article) {
return `/article/${article.slug}`;
}
// ✅ Хорошо - доменная логика в entities
// entities/article/lib/get-article-url.ts
export function getArticleUrl(article: Article) {
return `/article/${article.slug}`;
}
❌ Антипаттерн 2: God-компоненты в pages
FORBIDDEN: Размещать всю логику и UI в одном компоненте страницы
// ❌ Плохо - вся логика в pages
// pages/article-details/ui/article-details-page.tsx
export function ArticleDetailsPage() {
const { slug } = useParams();
const { data: article } = useArticle(slug);
const { mutate: favorite } = useFavorite();
const { mutate: follow } = useFollow();
const [comments, setComments] = useState([]);
// 200+ строк логики и UI
}
// ✅ Хорошо - композиция модулей
// pages/article-details/ui/article-details-page.tsx
export function ArticleDetailsPage() {
const { slug } = useParams();
return (
<div>
<ArticleDetail slug={slug} />
<ArticleComments slug={slug} />
</div>
);
}
❌ Антипаттерн 3: Циклические зависимости
FORBIDDEN: Создавать циклические зависимости между модулями
// ❌ Плохо - циклическая зависимость
// entities/article/model/use-article.ts
import { getCurrentUser } from '@/entities/user'; // user зависит от article
// entities/user/model/use-user.ts
import { getUserArticles } from '@/entities/article'; // article зависит от user
// ✅ Хорошо - композиция на более высоком уровне
// widgets/user-profile/ui/user-profile.tsx
import { UserCard } from '@/entities/user';
import { ArticleList, useUserArticles } from '@/entities/article';
export function UserProfile({ userId }: Props) {
const { data: articles } = useUserArticles(userId);
return (
<div>
<UserCard userId={userId} />
<ArticleList articles={articles} />
</div>
);
}
❌ Антипаттерн 4: Импорты между features
FORBIDDEN: Импортировать из одной feature в другую feature
// ❌ Плохо - feature зависит от другой feature
// features/article-create/model/use-article-form.ts
import { uploadImage } from '@/features/image-upload'; // Запрещено!
// ✅ Хорошо - вынести CRUD в shared/api
// shared/api/endpoints/media.api.ts
export async function uploadImage(file: File) {
const formData = new FormData();
formData.append('file', file);
return apiClient.post('/upload', formData);
}
// features/article-create/model/use-article-form.ts
import { uploadImage } from '@/shared/api/endpoints/media.api';
// features/image-upload/ui/image-uploader.tsx
import { uploadImage } from '@/shared/api/endpoints/media.api';