# OSACL - Learnings
## Lazy Coding
- private field
- Method To Generate If nil
- Use Lock when dealing with slice
**Ex 1:**
```
package osaclcore
import (
"sync"
"gitlab.com/evatix-go/core/constants"
"gitlab.com/evatix-go/errorwrapper"
"gitlab.com/evatix-go/errorwrapper/errnew"
)
type Group struct {
ID string
Name string
members *UsersCollection
sync.Mutex
}
func (group *Group) IsMembersEmpty() bool {
return group.MembersLength() == 0
}
func (group *Group) MembersLength() int {
members, errWrapper := group.Members()
if errWrapper.HasError() {
return constants.Zero
}
return members.Length()
}
func (group *Group) Members() (*UsersCollection, *errorwrapper.Wrapper) {
if group.members == nil {
collection, errWrapper := getGroupMembers(group.Name)
if errWrapper.HasError() {
return nil, errWrapper
}
group.members = collection
}
return group.members, errnew.EmptyPtr
}
func (group *Group) MembersLock() (*UsersCollection, *errorwrapper.Wrapper) {
group.Lock()
defer group.Unlock()
return group.Members()
}
```
**Ex :2**
```
package osaclcore
import (
"strings"
"gitlab.com/evatix-go/core/constants"
"gitlab.com/evatix-go/core/coreindexes"
"gitlab.com/evatix-go/core/issetter"
)
type User struct {
ID string
Name string
GroupID string
Info *UserInfo
HomeDirectory string
Shell string
Email string
isPromptPasswordChangeNext issetter.Value
passwordStatus *PasswordStatus
}
func (user *User) IsPromptPasswordChangeNext() bool {
if user.isPromptPasswordChangeNext.IsUninitialized() {
passwordStatus := user.PasswordStatus()
user.isPromptPasswordChangeNext = issetter.GetBool(passwordStatus.IsPasswordExpired)
}
return user.isPromptPasswordChangeNext.IsTrue()
}
func (user *User) PasswordStatus() *PasswordStatus {
if user.passwordStatus == nil {
passwordStatus, errWrapper := getUserPasswordStatus(user.Name)
errWrapper.HandleError()
user.passwordStatus = passwordStatus
}
return user.passwordStatus
}
```
## Running code with error
```
1. By Adding errorwrapper into the struct as non-export, and update and keep it for future reference. Use if condition before generates to check error and return.
2. Panic to deal with the issue (if you are lazy use this but it depends where you are writing it, if it is from soft package like strhelper, it is not okay)
3. With another flag, redundant for this case. For flag : https://gitlab.com/evatix-go/core/-/blob/develop/issetter/issetter.go
```
## ErrorWrapper Adding Useful Messages To Detect Error Easily
```
if user == nil {
return deferrwrapper.NilPointer.
ConcatNewMessage("osuser : CreateOrUpdate")
}
```
## Nested Condition
[Deal Negative Logic First](https://hackmd.io/@akarimevatix/golang-review-guides#Multiple-nesting-avoid-examples)
**Exception :** Allowed To use Mutation
```
func DropCreate(user *osaclcore.User) *errorwrapper.Wrapper {
if user == nil {
return deferrwrapper.NilPointer.
ConcatNewMessage("osuser : DropCreate")
}
errWrapper := errnew.EmptyPtr
if IsExist(user) {
errWrapper = Delete(user)
}
return eithererr.OrEmpty(*errWrapper, *Create(user))
}
```
## CRUD Methods
```
DeleteByName
Delete (user)
Create(user)
IsExist(username)
IsExistUser(user)
CreateByName(username:str)
Also include methods like :
CreateMust(user) panics if error,
DeleteMust(user)
DeleteByNameMust(...)
CreateByNameSkipOnExist(userName:str) // don't create if exist
CreateSkipOnExist(user) // don't create if exist
....
```