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 admin31
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 admin54
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 mount44
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 entries52
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 anything60
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 mount44
useEffect(() => {45
const loaded = loadLastUsedLogins();46
setLogins(loaded);47
}, []);...