Refactoring Agent Examples
Eliminate duplication
View on desktop for interactive diff
📄 players/views.py
-18 lines+11 linesExtract Mixin
BEFOREAuth logic mixed with business logic
24
@method_decorator(login_required, name='dispatch')
25
class AdminManageUsersView(View):
29
def get(self, request, *args, **kwargs):
×2 DUPLICATED
30
# Check if the current user is an admin
31
try:
32
player = Player.objects.get(user=request.user)
33
if not player.is_admin:
34
return HttpResponseForbidden("...")
35
except Player.DoesNotExist:
36
return HttpResponseForbidden("...")
38
# Get all users...
...
...
52
def post(self, request, *args, **kwargs):
53
# Check if the current user is an admin
54
try:
55
player = Player.objects.get(user=request.user)
56
if not player.is_admin:
57
return HttpResponseForbidden("...")
58
except Player.DoesNotExist:
59
return HttpResponseForbidden("...")
61
# Handle user deletion...
NEW CLASSline 10
10
class AdminRequiredMixin(LoginRequiredMixin):
11
"""Mixin to require admin status."""
12
def dispatch(self, request, *args, **kwargs):
13
try:
14
player = Player.objects.get(user=request.user)
15
except Player.DoesNotExist:
16
return HttpResponseForbidden("...")
17
if not player.is_admin:
18
return HttpResponseForbidden("...")
19
return super().dispatch(request, *args, **kwargs)
AFTERAuth logic cleanly separated
38
class AdminManageUsersView(AdminRequiredMixin, View):
42
def get(self, request, *args, **kwargs):
43
# Get all players and map...
...
...
59
def post(self, request, *args, **kwargs):
60
# Handle user deletion...
Remove indirection
View on desktop for interactive diff
📄 pages/_app.tsx
-4 linesRemove Indirection
BEFOREUnnecessary wrapper function
42
<Layout>
43
<Component {...pageProps} />
44
<UserTracking />
USELESS WRAPPER
45
<LoginTracking />
46
</Layout>
...
...
118
function LoginTracking() {
119
return <LoginTracker />;
120
}
AFTERDirect component usage
42
<Layout>
43
<Component {...pageProps} />
44
<UserTracking />
45
<LoginTracker />
46
</Layout>
...
Separate logic
View on desktop for interactive diff
📄 features/auth/hooks.ts → features/auth/storage.ts
-25 lines+3 linesExtract Storage Logic
BEFOREStorage logic mixed with UI hook
...
40
export const useLastUsedLogin = () => {
41
const [logins, setLogins] = useState<LastUsedLogin[]>([]);
43
// Load from localStorage on mount
44
useEffect(() => {
UI HOOK+ STORAGE LOGIC
45
if (typeof window === "undefined") return;
47
try {
48
const stored = localStorage.getItem(STORAGE_KEY);
49
if (stored) {
50
const parsed = JSON.parse(stored) as LastUsedLogin[];
51
// Filter out expired entries
52
const now = Date.now();
53
const valid = parsed.filter(
54
(login) =>
55
now - login.timestamp < EXPIRATION_DAYS * 24 * 60 * 60 * 1000,
56
);
57
setLogins(valid);
59
// Update localStorage if we filtered anything
60
if (valid.length !== parsed.length) {
61
localStorage.setItem(STORAGE_KEY, JSON.stringify(valid));
62
}
63
}
64
} catch (error) {
65
console.error("Failed to load last used logins:", error);
66
}
67
}, []);
...
NEW MODULEfeatures/auth/storage.ts
Separated Storage Logic45
export function loadLastUsedLogins(): LastUsedLogin[] {
46
const stored = safeGetJson<LastUsedLogin[]>(
47
localStorage,
48
LAST_USED_STORAGE_KEY,
49
);
...
// Filter expired, update storage...
62
}
AFTERUI HOOK ONLY
Clean separation...
40
export const useLastUsedLogin = () => {
41
const [logins, setLogins] = useState<LastUsedLogin[]>([]);
43
// Load from localStorage on mount
44
useEffect(() => {
45
const loaded = loadLastUsedLogins();
46
setLogins(loaded);
47
}, []);
...