---
# System prepended metadata

title: OSACL - Learnings

---

# 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
....
```